何时调用CanExecute

本文关键字:CanExecute 调用 何时 | 更新日期: 2023-09-27 17:51:26

在演示中,我有一个按钮来切换bool字段isAsking。我创建了一个命令,只有当isAsking==true .

一按Toggle键,okButton.IsEnable立即发生变化,说明命令找到了isAsking的变化。

我感到非常困惑,为什么命令对象注意到一个字段的变化。何时调用CanExecute ?

虽然写了一段时间的WPF应用程序,我是新的WPF命令。请给这个案例一个解释,如果可能的话,指出一些相关的文章或博客(我已经读了太多关于剪切/粘贴命令的文章)。

<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>

后台代码:

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

何时调用CanExecute

技术上的答案是,只要引发CommandManager.RequerySuggested事件,就会调用CanExecute。根据文档,这将是…

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

实际上,这只是意味着您不需要担心何时调用CanExecute: WPF将在它认为合适的时候调用它,根据我的经验,这几乎总是可以满足您的需求。

这个例外是,如果你有一个后台任务,将导致CanExecute改变它的返回值基于一些不是由UI触发的东西。在这种情况下,您可能需要手动强制WPF运行时重新查询CanExecute,这可以通过调用CommandManager.InvalidateRequerySuggested

来实现。

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

通过检查。net框架源代码,作者发现CommandManager本身不检测条件,而不是当Keyboard.KeyUpEvent, Mouse.MouseUpEvent, Keyboard.GotKeyboardFocusEventKeyboard.LostKeyboardFocusEvent发生时,它将重新评估CanExecute方法。

这篇文章还包括其他信息,但以上部分对我来说已经足够了

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

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

CommandManager.RequerySuggested事件引发

当命令检测到对命令源的更改时manager,在你的例子中是Window。因此,当单击按钮时,commandManager引发RequerySuggested事件,并因此执行为命令注册的CanExecute谓词。

另外,CommandManager有一个静态方法- InvalidateRequerySuggested,它强制CommandManager引发requery建议事件。因此,您也可以调用它来手动验证您的命令

默认展开注释

假设我们有以下

public class SomeClass : ViewModelBase {
   public ICommand ConnectButtonCommand { get; }
   public SomeClass(){
      //...
      ConnectButtonCommand = new DelegateCommand(ConnectButton_Click, ConnectButton_CanExecute);
      //...
   }
   public DoSomething(){
      //do something that affects the result of ConnectButton_CanExecute
      ((DelegateCommand)ConnectButtonCommand).RaiseCanExecuteChanged();
   }
   private void ConnectButton_Click() {/*...*/}
   private bool ConnectButton_CanExecute() {/*...*/}
}

我正在开发一个使用Prism for MVVM的UWP应用程序。通用windows平台与WPF非常相似