.net WPF - 如何强制命令通过其 CommandBindings 重新评估“CanExecute”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1340302/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 13:13:15  来源:igfitidea点击:

WPF - How to force a Command to re-evaluate 'CanExecute' via its CommandBindings

.netwpfcommandcommandbinding

提问by Drew Noakes

I have a Menuwhere each MenuItemin the hierarchy has its Commandproperty set to a RoutedCommandI've defined. The associated CommandBindingprovides a callback for the evaluation of CanExecutewhich controls the enabled state of each MenuItem.

我有一个层次结构Menu中的每个属性都设置为我定义的属性。关联提供了一个用于评估的回调,该回调控制每个 的启用状态。MenuItemCommandRoutedCommandCommandBindingCanExecuteMenuItem

This almostworks. The menu items initially come up with the correct enabled and disabled states. However when the data that my CanExecutecallback uses changes, I need the command to re-request a result from my callback in order for this new state to be reflected in the UI.

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

There do not appear to be any public methods on RoutedCommandor CommandBindingfor this.

似乎没有任何关于此RoutedCommandCommandBinding为此的公共方法。

Note that the callback is used again when I click or type into the control (I guess it's triggered on input because mouse-over doesn't cause the refresh).

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

回答by Arcturus

Not the prettiest in the book, but you can use the CommandManager to invalidate all commandbinding:

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

CommandManager.InvalidateRequerySuggested();

See more info on MSDN

MSDN上查看更多信息

回答by CodingWithSpike

For anyone who comes across this later; If you happen to be using MVVM and Prism, then Prism's DelegateCommandimplementation of ICommandprovides a .RaiseCanExecuteChanged()method to do this.

对于以后遇到此问题的任何人;如果您碰巧使用 MVVM 和 Prism,那么 Prism 的DelegateCommand实现ICommand提供了一种.RaiseCanExecuteChanged()方法来执行此操作。

回答by Bek Raupov

I couldnt use CommandManager.InvalidateRequerySuggested();because I was getting performance hit.

我无法使用,CommandManager.InvalidateRequerySuggested();因为我的性能受到了影响。

I have used MVVM Helper's Delegating command, which looks like below (i have tweaked it a bit for our req). you have to call command.RaiseCanExecuteChanged()from VM

我使用了MVVM Helper的 Delegating 命令,如下所示(我已经根据我们的要求对其进行了一些调整)。你必须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);
}

回答by Andrue Cope

If you have rolled your own class that implements ICommandyou can lose a lot of the automatic status updates forcing you to rely on manual refreshing more than should be needed. It can also break InvalidateRequerySuggested(). The problem is that a simple ICommandimplementation fails to link the new command to the CommandManager.

如果您已经推出了自己的实现类,ICommand您可能会失去很多自动状态更新,从而迫使您更多地依赖手动刷新。它也可以打破InvalidateRequerySuggested()。问题是一个简单的ICommand实现无法将新命令链接到CommandManager.

The solution is to use the following:

解决方法是使用以下方法:

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

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

This way subscribers attach to CommandManagerrather than your class and can properly participate in command status changes.

通过这种方式,订阅者可以附加到CommandManager您的班级而不是您的班级,并且可以正确参与命令状态更改。

回答by Fabio Angela

I've implemented a solution to handle property dependency on commands, here the link https://stackoverflow.com/a/30394333/1716620

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

thanks to that you'll end up having a command like this:

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

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

回答by rmustakos

This is what worked for me: Put the CanExecute before the Command in the XAML.

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