CanExecute什么时候叫?

时间:2013-01-12 15:22:50

标签: c# .net 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>

代码隐藏:

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 个答案:

答案 0 :(得分:31)

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

  

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

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

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

来执行此操作

答案 1 :(得分:25)

我尝试搜索“CommandManager检测到条件”并到达this exellent article

通过检查.NET Framework源代码,作者发现CommandManager本身并不检测条件,而不是Keyboard.KeyUpEventMouse.MouseUpEventKeyboard.GotKeyboardFocusEvent,或Keyboard.LostKeyboardFocusEvent发生,它将重新评估CanExecute方法。

该文章包含其他信息,但上述部分对我来说已经足够了。

答案 2 :(得分:8)

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

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

CommandManager.RequerySuggested事件被提出

  

命令检测到命令源的更改   在你的情况下经理是窗口。因此,当单击按钮时,commandManager会引发RequerySuggested事件,从而执行为您的命令注册的CanExecute谓词。

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

答案 3 :(得分:0)

默认情况下扩展comment

假设我们有以下内容

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非常相似。