35

在演示中,我有一个按钮来切换 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;
    }
}
4

4 回答 4

40

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

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

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

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

于 2013-01-12T15:43:10.220 回答
32

我尝试搜索“CommandManager 检测条件”并找到这篇出色的文章

通过查看.NET Framework源码,作者发现它CommandManager本身并没有检测到条件,而不是当Keyboard.KeyUpEvent, Mouse.MouseUpEvent, Keyboard.GotKeyboardFocusEvent, orKeyboard.LostKeyboardFocusEvent发生时,它会重新评估CanExecute方法。

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

于 2013-01-13T02:39:40.923 回答
9

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

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

CommandManager.RequerySuggested引发了事件

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

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

于 2013-01-13T08:34:08.903 回答
1

默认情况下展开评论

假设我们有以下

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 用于 MVVM 的 UWP 应用程序。通用 Windows 平台与 WPF 非常相似。

于 2019-03-15T04:55:39.897 回答