CanExecute什么时候叫?

Gqq*_*big 31 .net c# wpf

在演示中,我有一个按钮来切换bool字段isAsking.我创建一个只能在执行时执行的命令isAsking==true.

按下切换按钮后,okButton.IsEnable立即更改,这表示命令找到了更改isAsking.

我觉得很困惑为什么命令对象会注意到字段的变化,什么时候CanExecute会被调用?

虽然编写WPF应用程序已有一段时间了,但我是WPF Command的新手.请对此案例进行解释,如果可能的话,请指出一些相关的文章或博客(我已经阅读了太多关于剪切/粘贴命令的文章).

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        x:Class="WpfApplication1.MainWindow"
        Title="MainWindow" Height="350" Width="525" x:Name="mainWindow" >
    <StackPanel>
        <Button Name="okButton" Content="Ok" />
        <Button Content="Toggle"  Click="Button_Click_1"/>
    </StackPanel>
</Window>
Run Code Online (Sandbox Code Playgroud)

代码隐藏:

public partial class MainWindow : Window
{
    private bool isAsking;

    public MainWindow()
    {
        InitializeComponent();

        CommandBinding cb = new CommandBinding();
        cb.Command = okCommand;
        cb.CanExecute += CanOKExecute;
        cb.Executed += cb_Executed;
        mainWindow.CommandBindings.Add(cb);
        okButton.Command = okCommand;
    }

    private RoutedCommand okCommand = new RoutedCommand("ok", typeof(MainWindow));


    void cb_Executed(object sender, ExecutedRoutedEventArgs e)
    {

    }

    void CanOKExecute(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = isAsking;
    }

    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        isAsking = !isAsking;
    }
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*rex 33

技术答案是CanExecute每当CommandManager.RequerySuggested引发事件时都会调用它.根据文档,这将是......

...当CommandManager检测到可能会改变命令执行能力的条件时.

实际上,这只意味着您不必担心何时CanExecute被调用:WPF会在认为合适的时候调用它,根据我的经验,这几乎总能满足您的要求.

例外情况是,如果您有后台任务,将导致CanExecute根据UI未触发的内容更改其返回值.在这种情况下,您可能需要手动强制WPF运行时重新查询CanExecute可以通过调用执行的操作CommandManager.InvalidateRequerySuggested

  • 或者,如果它是Prism`委托命令` - 在`Command`本身上调用`RaiseCanExecuteChanged()`. (7认同)
  • @Default是的.同样,如果它是你自己的`ICommand`实现,你可以在命令上手动引发`CanExecuteChanged`事件 (4认同)

Gqq*_*big 26

我尝试搜索"CommandManager检测条件"并找到这篇优秀的文章.

通过检查.NET Framework的源代码,笔者认为,CommandManager本身并不检测条件,而不是时Keyboard.KeyUpEvent,Mouse.MouseUpEvent,Keyboard.GotKeyboardFocusEvent,或Keyboard.LostKeyboardFocusEvent发生时,它会重新评估CanExecute方法.

这篇文章包含其他信息,但上面的部分对我来说已经足够了.

  • 我对这种默认行为感到有点骇然.如果一个表单有很多控件并且CanExecute方法写得不够理想,那么这是一个非常大量的潜在无用CanExecute评估不是吗?无法了解架构如何扩展? (9认同)

Roh*_*ats 8

RoutedCommand包含一个CanExecuteChanged内部挂钩CommandManager.RequerySuggested事件的事件 -

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }
Run Code Online (Sandbox Code Playgroud)

CommandManager.RequerySuggested事件引发

只要命令管理器检测到命令源的更改,在您的情况下是Window.因此,当单击按钮时,commandManager会引发RequerySuggested事件,从而执行为您的命令注册的CanExecute谓词.

此外,CommandManager有一个静态方法 - InvalidateRequerySuggested强制CommandManager引发RequerySuggestedEvent.因此,您可以调用它来手动验证命令.