WPF - How to force a Command to re-evaluate 'CanExecute' via its CommandBindings
Solution 1:
Not the prettiest in the book, but you can use the CommandManager to invalidate all commandbinding:
CommandManager.InvalidateRequerySuggested();
See more info on MSDN
Solution 2:
For anyone who comes across this later; If you happen to be using MVVM and Prism, then Prism's DelegateCommand
implementation of ICommand
provides a .RaiseCanExecuteChanged()
method to do this.
Solution 3:
I couldnt use CommandManager.InvalidateRequerySuggested();
because I was getting performance hit.
I have used MVVM Helper's Delegating command, which looks like below (i have tweaked it a bit for our req). you have to call command.RaiseCanExecuteChanged()
from VM
public event EventHandler CanExecuteChanged
{
add
{
_internalCanExecuteChanged += value;
CommandManager.RequerySuggested += value;
}
remove
{
_internalCanExecuteChanged -= value;
CommandManager.RequerySuggested -= value;
}
}
/// <summary>
/// This method can be used to raise the CanExecuteChanged handler.
/// This will force WPF to re-query the status of this command directly.
/// </summary>
public void RaiseCanExecuteChanged()
{
if (canExecute != null)
OnCanExecuteChanged();
}
/// <summary>
/// This method is used to walk the delegate chain and well WPF that
/// our command execution status has changed.
/// </summary>
protected virtual void OnCanExecuteChanged()
{
EventHandler eCanExecuteChanged = _internalCanExecuteChanged;
if (eCanExecuteChanged != null)
eCanExecuteChanged(this, EventArgs.Empty);
}
Solution 4:
If you have rolled your own class that implements ICommand
you can lose a lot of the automatic status updates forcing you to rely on manual refreshing more than should be needed. It can also break InvalidateRequerySuggested()
. The problem is that a simple ICommand
implementation fails to link the new command to the CommandManager
.
The solution is to use the following:
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequerySuggested();
}
This way subscribers attach to CommandManager
rather than your class and can properly participate in command status changes.
Solution 5:
I've implemented a solution to handle property dependency on commands, here the link https://stackoverflow.com/a/30394333/1716620
thanks to that you'll end up having a command like this:
this.SaveCommand = new MyDelegateCommand<MyViewModel>(this,
//execute
() => {
Console.Write("EXECUTED");
},
//can execute
() => {
Console.Write("Checking Validity");
return PropertyX!=null && PropertyY!=null && PropertyY.Length < 5;
},
//properties to watch
(p) => new { p.PropertyX, p.PropertyY }
);