WPF - 如何强制命令通过其CommandBindings重新评估'CanExecute'

问题描述 投票:121回答:6

我有一个Menu,其中层次结构中的每个MenuItem都将其Command属性设置为我定义的RoutedCommand。相关的CommandBinding为评估CanExecute提供了一个回调,MenuItem控制每个CanExecute的启用状态。

这几乎可行。菜单项最初会显示正确的启用和禁用状态。但是当我的RoutedCommand回调使用的数据发生变化时,我需要命令从我的回调中重新请求结果,以便在UI中反映这种新状态。

CommandBindingCommandManager.InvalidateRequerySuggested(); 上似乎没有任何公开方法。

请注意,当我单击或键入控件时再次使用回调(我猜它是在输入时触发的,因为鼠标悬停不会导致刷新)。

.net wpf command commandbinding
6个回答
164
投票

书中不是最漂亮的,但您可以使用CommandManager使所有命令绑定无效:

MSDN

查看有关DelegateCommand的更多信息


83
投票

对于后来遇到此事的人;如果你恰好使用MVVM和Prism,那么Prism的ICommand实现.RaiseCanExecuteChanged()提供了CommandManager.InvalidateRequerySuggested();方法来做到这一点。


25
投票

我无法使用qazxsw poi,因为我的性能受到了打击。

我使用过MVVM Helper的Delegating命令,看起来如下(我已经调整了一下我们的req)。你必须从VM调用command.RaiseCanExecuteChanged()

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

14
投票

如果您已经推出了自己的实现ICommand的类,那么您可能会丢失大量自动状态更新,这会导致您依赖手动刷新而不是需要更多。它也可以打破InvalidateRequerySuggested()。问题是简单的ICommand实现无法将新命令链接到CommandManager

解决方案是使用以下内容:

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

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

这样订阅者可以附加到CommandManager而不是您的类,并且可以正确地参与命令状态更改。


2
投票

我已经实现了一个处理命令属性依赖的解决方案,这里是链接https://stackoverflow.com/a/30394333/1716620

多亏了你最终会得到这样的命令:

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

-1
投票

这对我有用:在XAML中将CanExecute放在命令之前。

© www.soinside.com 2019 - 2024. All rights reserved.