应该如何实现`ICommand.CanExecuteChanged`?

时间:2017-09-28 17:50:24

标签: c# wpf mvvm weak-references relaycommand

背景

在查看Josh Smith关于CommandGroup的文章时,我注意到互联网上有很多关于如何实施ICommand.CanExecuteChanged的评论。

在StackOverflow上发布了一个类似的问题here,但是

  1. 我觉得没有一个明确的答案,
  2. 评论中没有足够的空间来添加其他上下文。
  3. 供参考:

    1. Josh Smith关于CommandGroup的原始article使用简单的.NET事件
    2. Josh Smith的RelayCommand使用CommandManager implementation CanExecuteChanged
    3. Microsoft自己的RoutedCommand使用CommandManager implementation CanExecuteChanged
    4. Microsoft自己的PRISM库(版本:6)也uses一个简单的.NET事件(以前的版本使用弱引用)
    5. 我的问题

      我对WPF比较陌生,我想知道如何在Josh Smith的CanExecuteChanged中实现CommandGroup事件以避免任何意外行为或内存泄漏?

      补充阅读

      Josh Smith: Aggregating WPF Commands with CommandGroup

      Josh Smith: WPF apps with the MVVM design pattern

      StackOverflow: Is Josh Smith's implementation of the RelayCommand flawed?

      StackOverflow: comment about CanExecuteChanged

      Microsoft: RoutedCommand

      PRISM 6: DelegateCommandBase

1 个答案:

答案 0 :(得分:0)

让我们假设您将命令绑定到按钮。当即将呈现该按钮时,它将调用CanExecute()并根据结果将呈现为Enabled或Disabled。 当"它决定"时,WPF会自动调用CanExecute(),但是你永远不应该继续这种行为。

因此,当您实现ICommand时,声明一个类似UpdateCommand()的方法,当您决定时,它将引发有问题的事件。 例如,如果点击一个按钮开始一个缓慢的操作,应该在前一个按钮完成后再次触发,你应该将事件提高两次 - 一次是在开始操作之前,一次是在完成之后。

没有"实现ICommand.CanExecuteChanged"的最佳方法。可能这是不通过框架发布ICommand的默认实现的部分原因。 大多数MVVM框架提供默认实现:RelayCommand,ActionCommand,ParameterCommand,AsyncCommand等。 他们只是让事情变得更容易 - 通过代表,你准备好了。 Josh Smith的文章解决了另一个问题,即在XAML中链接多个路由命令的简洁方法。

一般来说:

  1. 将ICommand与MVVM一起使用
  2. 在创建可重用控件时使用RoutedCommand,并且您希望命令冒泡可视化树,以便感兴趣的后代可以处理它
  3. 您可以使用Decorator设计模式并装饰所有命令, 这样你就可以添加一个上层功能,比如只为特权用户激活的命令,一次禁用所有命令等等。只需确保装饰器订阅实际命令的CanExecuteChanged并重新激活它的事件。代表