WPF – Как заставить команду переоценить «CanExecute» через свой CommandBindings
У меня есть Menu
котором каждый элемент MenuItem
в иерархии имеет свойство Command
установленное в RoutedCommand
я определил. CanExecute
CommandBinding
обеспечивает обратный вызов для оценки CanExecute
который управляет включенным состоянием каждого MenuItem
.
Это почти работает. Первоначально элементы меню вызывают правильные состояния включения и выключения. Однако, когда данные, которые CanExecute
обратный вызов CanExecute
используют изменения, мне нужна команда для повторного запроса результата из моего обратного вызова, чтобы это новое состояние отражалось в пользовательском интерфейсе.
По-видимому, для этого не существуют общедоступные методы RoutedCommand
или CommandBinding
.
- Обновление ObservableCollection в отдельном streamе
- Как должна ViewModel закрыть форму?
- Как отключить эффекты MouseOver для кнопки в WPF?
- Отключить ключ ускорителя ярлыков WPF (текст подчеркивания отсутствует)
- Установите элемент управления веб-браузером WPF для использования режима IE10
Обратите внимание, что обратный вызов используется снова, когда я нажимаю или набираю элемент управления (я предполагаю, что он запускается на входе, потому что переключение мыши не вызывает обновление).
- Как применить правило пользовательской сортировки к WPF DataGrid?
- Связывание ComboBox SelectedItem с использованием MVVM
- Используйте Messenger MVVM Light для передачи значений между View Model
- Как использовать значок, который является ресурсом в WPF?
- В WPF есть свойство DesignMode?
- WPF показывает диалог перед основным окном
- Как преобразовать ImageSource в массив байтов?
- WPF Image Pan, Zoom и Scroll со слоями на canvasе
Не самый красивый в книге, но вы можете использовать CommandManager, чтобы аннулировать все команды:
CommandManager.InvalidateRequerySuggested();
Подробнее о MSDN
Для тех, кто сталкивается с этим позже; Если вы используете MVVM и Prism, то реализация функции ICommand
в .RaiseCanExecuteChanged()
DelegateCommand
Prism предоставляет метод .RaiseCanExecuteChanged()
для этого.
Я не мог использовать CommandManager.InvalidateRequerySuggested();
потому что я получал удар производительности.
Я использовал команду делегирования MVVM Helper , которая выглядит как ниже (я немного изменил ее для нашего req). вам нужно вызвать command.RaiseCanExecuteChanged()
из VM
public event EventHandler CanExecuteChanged { add { _internalCanExecuteChanged += value; CommandManager.RequerySuggested += value; } remove { _internalCanExecuteChanged -= value; CommandManager.RequerySuggested -= value; } } /// /// This method can be used to raise the CanExecuteChanged handler. /// This will force WPF to re-query the status of this command directly. /// public void RaiseCanExecuteChanged() { if (canExecute != null) OnCanExecuteChanged(); } /// /// This method is used to walk the delegate chain and well WPF that /// our command execution status has changed. /// protected virtual void OnCanExecuteChanged() { EventHandler eCanExecuteChanged = _internalCanExecuteChanged; if (eCanExecuteChanged != null) eCanExecuteChanged(this, EventArgs.Empty); }
Если вы применили свой собственный class, который реализует ICommand
вы можете потерять много автоматических обновлений статуса, заставляя вас полагаться на ручное обновление более чем необходимо. Он также может разорвать InvalidateRequerySuggested()
. Проблема в том, что простая реализация ICommand
не связывает новую команду с CommandManager
.
Решение состоит в том, чтобы использовать следующее:
public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public void RaiseCanExecuteChanged() { CommandManager.InvalidateRequerySuggested(); }
Таким образом, подписчики подключаются к CommandManager
а не к вашему classу, и могут нормально участвовать в изменениях состояния команды.
Я реализовал решение для обработки зависимости свойств от команд, здесь ссылка https://stackoverflow.com/a/30394333/1716620
благодаря этому вы получите команду вроде этого:
this.SaveCommand = new MyDelegateCommand(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 } );