The ICommand
interface is the following:
public interface ICommand
{
// two methods
bool CanExecute(object parameter);
void Execute(object parameter);
// one event
event EventHandler CanExecuteChanged;
}
The CanExecuteChanged
event should be raised any time you want to indicate that the CanExecute
method should be checked/called by WPF. Whoever implements ICommand
should raise the event and whoever needs to refresh the button enabled state on the GUI (the WPF system) should register for and handle the event and it calls CanExecute
.
In Josh Smith's RelayCommand
class, he uses WPF's built-in CommandManager
class to raise CanExecuteChanged
:
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
In essence, WPF's CommandManager
is a singleton that listening for all sorts of routed events: KeyUpEvent, MouseUpEvent, etc... and then tells everyone "hey something interesting happened" by raising its RequerySuggested
event. So if you are using RelayCommand
, your CanExecute
will get called every time CommandManager
thinks something interesting happened on the GUI (even if it has nothing to do with your collection). If you have 50 commands, each time you key up, it's rechecking all 50 commands. So yes, this could be a performance issue. However, if your logic in your CanExecute
method is really simple, it's probably a non issue. Takeaway point: don't make database or network API calls in the CanExecute
method.
The alternative to piggybacking off CommandManager.RequerySuggested
to raise the ICommand.CanExecuteChanged
event is to roll-your-own version of RelayCommand
where you do your own checking and raise CanExecuteChanged
manually, or look at the Prism framework's DelegateCommand
class, where they do not tie into CommandManager
and you have to manually raise the CanExecuteChanged
event, which you could probably do by creating a listener for PropertyChanged
and then raising CanExecuteChanged
on the command.
I agree with @Will above though. RelayCommand
will probably work over 80% of the time without issues. If you do start finding performance issues, then you can create your own version of RelayCommand or use the Prism DelegateCommand
and raise CanExecuteChanged
manually.