Search code examples
c#wpfmvvminotifypropertychangedicommand

Why CanExecute only get called when it's initialized in the constructor of the view model?


I have a Command property, with this definition in the view model:

public RelayCommand SaveCommand => new RelayCommand(OnSave, CanSave);

whenever the ErrorsChanged of the INotifyDataErrorInfo is fired, RaiseCanExecuteChanged is called in the RelayCommand class, to enable/disable the button:

public void RaiseCanExecuteChanged()
        {
            CanExecuteChanged(this, EventArgs.Empty);
        }

the two delegates of the command are set in the constructor:

public RelayCommand(Action executeMethod, Func<bool> canExecuteMethod)
        {
            _TargetExecuteMethod = executeMethod;
            _TargetCanExecuteMethod = canExecuteMethod;
        }

but when the error state changed (when RaiseCanExecuteChanged is called) the CanSave method doesn't get called, after a while I changed the Command initialization way to be set in the constructor instead:

    public AddEditCustomerViewModel()
    {
        SaveCommand = new RelayCommand(OnSave, CanSave);
    }
    public RelayCommand SaveCommand {get;}

and it works! but why?


Solution

  • When you initialize the SaveCommad in the view model's constructor, it only run once when the view model is initialized, but When you define SaveCommand using:

    public RelayCommand SaveCommand => new RelayCommand(OnSave, CanSave);
    

    You are actually doing:

    public RelayCommand SaveCommand {
        get {
            return new RelayCommand(OnSave, CanSave);
        }
    }
    

    In such case Whenever the getter of SaveCommand is called, it returns a new instance of RelayCommand. So when the RaiseCanExecuteChanged is called, it may not be the same object that's currently binding to the UI, hence failed to update the state