Интерфейс ICommand
выглядит следующим образом:
public interface ICommand
{
// two methods
bool CanExecute(object parameter);
void Execute(object parameter);
// one event
event EventHandler CanExecuteChanged;
}
Событие CanExecuteChanged
должно вызываться всякий раз, когда вы хотите указать, что метод CanExecute
должен быть проверен / вызван WPF. Тот, кто реализует ICommand
, должен вызвать событие, а тот, кто должен обновить состояние включения кнопки в графическом интерфейсе (система WPF), должен зарегистрироваться и обработать событие, и он вызывает CanExecute
.
В классе RelayCommand
Джоша Смита он использует встроенный в WPF класс CommandManager
для повышения CanExecuteChanged
:
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
По сути, WPF CommandManager
- это синглтон, который прослушивает все виды перенаправленных событий: KeyUpEvent, MouseUpEvent и т. Д., А затем сообщает всем «эй, что-то интересное произошло», вызывая событие RequerySuggested
. Поэтому, если вы используете RelayCommand
, ваш CanExecute
будет вызываться каждый раз, когда CommandManager
думает, что в GUI происходит что-то интересное (даже если это не имеет никакого отношения к вашей коллекции). Если у вас есть 50 команд, каждый раз, когда вы нажимаете клавишу, она перепроверяет все 50 команд. Так что да, это может быть проблемой производительности. Однако, если ваша логика в вашем CanExecute
методе действительно проста, это, вероятно, не проблема. Вывод: не выполняйте вызовы базы данных или сетевого API в методе CanExecute
.
Альтернативой откату CommandManager.RequerySuggested
для поднятия события ICommand.CanExecuteChanged
является свертывание собственной версии RelayCommand
, где вы выполняете свою собственную проверку и поднимаете CanExecuteChanged
вручную, или смотрите на каркас Prism * Класс 1032 *, где они не связаны с CommandManager
, и вам нужно вручную вызвать событие CanExecuteChanged
, что вы, вероятно, могли бы сделать, создав прослушиватель для PropertyChanged
и затем подняв CanExecuteChanged
по команде.
Я согласен с @Will выше, хотя. RelayCommand
, вероятно, будет работать более 80% времени без проблем. Если вы начнете находить проблемы с производительностью, то вы можете создать свою собственную версию RelayCommand или использовать Prism DelegateCommand
и повысить CanExecuteChanged
вручную.