Подтвердить что ты не робот

WPF - Как заставить команду переоценить "CanExecute" через свой CommandBindings

У меня есть Menu, где каждый MenuItem в иерархии имеет свойство Command, установленное в RoutedCommand, которое я определил. Связанный CommandBinding обеспечивает обратный вызов для оценки CanExecute, который управляет включенным состоянием каждого MenuItem.

Это почти работает. Первоначально элементы меню вызывают правильные состояния включения и выключения. Однако, когда данные, которые мой обратный вызов CanExecute использует изменения, мне нужна команда для повторного запроса результата из моего обратного вызова, чтобы это новое состояние отображалось в пользовательском интерфейсе.

Для этого не существуют общедоступные методы для RoutedCommand или CommandBinding.

Обратите внимание, что обратный вызов используется снова, когда я нажимаю или набираю элемент управления (я предполагаю, что он активирован на входе, потому что переключение с помощью мыши не вызывает обновление).

4b9b3361

Ответ 1

Не самый красивый в книге, но вы можете использовать CommandManager для аннулирования всех команд:

CommandManager.InvalidateRequerySuggested();

Подробнее о MSDN

Ответ 2

Для тех, кто сталкивается с этим позже; Если вы используете MVVM и Prism, то реализация DelegateCommand призма DelegateCommand предоставляет метод .RaiseCanExecuteChanged() для этого.

Ответ 3

Я не мог использовать CommandManager.InvalidateRequerySuggested();, потому что получал удар производительности.

Я использовал MVVM Helper Делегирующая команда, которая выглядит как ниже (я немного изменил ее для нашего req). вы должны вызвать command.RaiseCanExecuteChanged() из 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);
}

Ответ 4

Если вы перевернули свой собственный класс, который реализует ICommand, вы можете потерять много автоматических обновлений статуса, заставляя вас полагаться на ручное обновление больше, чем нужно. Он также может сломать InvalidateRequerySuggested(). Проблема в том, что простая реализация ICommand не связывает новую команду с CommandManager.

Решение состоит в том, чтобы использовать следующее:

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void RaiseCanExecuteChanged()
    {
        CommandManager.InvalidateRequerySuggested();
    }

Таким образом, подписчики подключаются к CommandManager, а не к вашему классу, и могут нормально участвовать в изменениях статуса команды.

Ответ 5

Я реализовал решение для обработки зависимости свойств от команд, здесь ссылка fooobar.com/info/53503/...

благодаря этому вы получите команду вроде этого:

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 }
 );