How to bind to a property with access only

I have a special custom list in the wpf window. I also have a viewmodel class with Property Changed that looks like this:

public bool HasChanges { get { return customers.Any(customer => customer.Changed); } } 

So, I would like to bind my Save button to this property:

 <Button IsEnabled="{Binding HasChanges, Mode=OneWay}"... 

My question is: how to update the "Save" button if one of the lines in the list has changed?

+6
source share
5 answers

The correct way to work with buttons is to implement the ICommand interface. Here is an example from my solution:

 public class RelayCommand : ICommand { readonly Action<object> _execute; readonly Predicate<object> _canExecute; public RelayCommand(Action<object> execute) : this(execute, null) { } public RelayCommand(Action<object> execute, Predicate<object> canExecute) { if (execute == null) throw new ArgumentNullException("execute"); _execute = execute; _canExecute = canExecute; } #region ICommand Members public bool CanExecute(object parameter) { return _canExecute == null ? true : _canExecute(parameter); } public void Execute(object parameter) { _execute(parameter); } public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } #endregion } 

You can then attach the following command to this button:

 <Button Command="{Binding MyCommand}" .../> 

It remains to declare the ICommand property on your view model:

 public ICommand MyCommand { get; private set; } //in constructor: MyCommand = new RelayCommand(_ => SomeActionOnButtonClick(), _ => HasChanges); 

The button state is automatically updated with most changes. If for some reason this is not the case, you can force the update by calling CommandManager.InvalidateRequerySuggested

+2
source

In order for WPF to respond to property changes, the class must implement the INotifyPropertyChanged interface. You need to send notifications every time a client changes, for example:

 class CustomerList : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private List<Customer> customers = ... public bool HasChanges { get { return customers.Any(customer => customer.Changed); } } // Callers who change customers inside your list must call this method public void ChangeCustomer(Customer c) { // Do whatever you need to do, ... ... // then send out the notification to WPF OnPropertyChanged("HasChanges"); } protected void OnPropertyChanged(string name) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(name)); } } } 
+2
source

Your ViewModel model should implement INotifyPropertyChanged and should raise a PropertyChanged event for HasChanges when you change the client in customers

Update:

If clients implement INotifyPropertyChanged and clients are an observable collection. You can also subscribe, depending on the desubscribe action for all customers in the CollectionChangedEvent your customers collection.

+1
source

If your ViewModel implements INotifyPropertyChanged, you just need to call the OnPropertyChanged () method on HasChanges. With Prism, the equivalent method is RaisePropertyChanged.

However, with MVVM, you can put this test in the CanExecute method of your command, bound to the Command property. This will automatically process IsEnabled.

0
source

The button must somehow receive notifications. In your case, you are probably implementing the INotifyPropertyChanged interface in your viewmodel. When your list line changes, you should raise the PropertyChanged event for the HasChanges property. Changes should be noticed, however, in you viewmodel and the event should be raised there. As another solution, since you have a viewmodel, you can use the command on your button, and CanExecute will have logic that returns true or false, which should also be noted by you when changes have occurred.

0
source

Source: https://habr.com/ru/post/952016/


All Articles