【问题标题】:When is CanExecute called?何时调用 CanExecute?
【发布时间】:2012-12-27 00:19:32
【问题描述】:

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

一旦我按下切换按钮,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;
    }
}

【问题讨论】:

    标签: c# .net wpf


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 或者,如果是 Prism DelegateCommand - 在 Command 本身上调用 RaiseCanExecuteChanged()。
    • @默认为真。同样,如果是您自己的 ICommand 实现,您可以在命令上手动引发 CanExecuteChanged 事件
    • Doyyy.. 我完全忘记了ICommand.. 中的那个事件。我认为 Prism 正在做某事 :)
    • 鉴于您无法控制它的运行频率,您需要确保它不会做很多事情,例如不要查询其中的数据库。
    【解决方案2】:

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

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

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

    【讨论】:

    • 我对这种默认行为有点震惊。如果一个表单有很多控件并且 CanExecute 方法的编写不是最理想的,那么这就是大量可能无用的 CanExecute 评估,不是吗?无法了解架构的扩展方式?
    【解决方案3】:

    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。因此,您也可以调用它来手动验证您的命令。

    【讨论】:

      【解决方案4】:

      默认扩展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 非常相似。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-09-25
        • 1970-01-01
        • 2011-01-27
        • 1970-01-01
        • 2023-04-03
        • 1970-01-01
        • 2017-07-13
        相关资源
        最近更新 更多