【问题标题】:Should I check an ICommand's CanExecute method before calling Execute from procedural code?在从程序代码调用 Execute 之前,我应该检查 ICommand 的 CanExecute 方法吗?
【发布时间】:2011-10-20 01:28:15
【问题描述】:

在 XAML 中使用 ICommands 时,WPF 使用 CanExecute 方法来启用或禁用与命令关联的控件。但是如果我从程序代码中调用Execute 怎么办?我应该先检查CanExecute 以确保命令可以执行,还是应该Execute 为我处理这个检查?

换句话说,我应该这样做:

if (someCommand.CanExecute(parameter, target))
    someCommand.Execute(parameter, target);

或者只是这样:

someCommand.Execute(parameter, target);

【问题讨论】:

  • 为什么不把这部分作为 Execute() 的一部分?

标签: c# .net wpf icommand routed-commands


【解决方案1】:

好的风格会要求你应该做前者,首先检查 CanExecute。这将强制执行适当的分解和一致性。此外,如果您确实想使用绑定到按钮的此命令,它将按预期工作。

【讨论】:

  • 合同上,这感觉“更正确”。我还要补充一点,如果您正在检查的条件以任何方式依赖于命令外在的状态(因此可以由另一个线程等修改),您需要锁定 CanExecute/Execute 序列。
【解决方案2】:

您应该只调用 Execute 并让命令实现处理验证。 CanExecute 主要是为 UI 状态绑定提供的。

除了非常简单的单线程场景,即使您首先调用 CanExecute,也很容易出现竞争条件,即 CanExecute 和 Execute 调用之间的命令有效性发生变化,从而使对 CanExecute 的调用毫无意义。

【讨论】:

  • 我看不出竞态条件在调用 CanExecute 然后 Execute 与仅调用 Execute 的情况下会有什么不同。无论如何,这些调用将按顺序执行。如果您指的是后台线程,那么在 Execute 中间有一个上下文切换,就像在 CanExecute 和 Execute 之间有一个一样。
  • 正如您刚刚指出的那样,它们不一定会按顺序执行,即使它们是,如何阻止另一个线程在这两个顺序调用之间更改命令的基础数据或状态?而命令实现知道它正在运行的上下文,并且可以在需要时自动同步对共享数据的访问。它也最好在执行时确定命令是否有效。
  • 命令的基础数据可以在执行过程中的任何时候发生变化,而不管您是否在 Execute 调用或 CanExecute 调用中进行检查。但是,我确实看到了必要时同步访问的案例。不过我会争辩说,这只是少数情况,虽然在容易出现竞争条件的利基市场中是必要的,但在一般设计中,最好在风格上使用 CanExectue。
  • 如果同步访问数据,则数据无法更改。我的观点是,只有命令实现才能知道这是否有必要。此外,不存在“容易出现竞争条件的利基市场”:要么存在对数据的并发访问,在这种情况下需要保护它,要么没有。您似乎在争辩说,由于这种类型的竞争条件很少发生,因此可以忽略它们。这是一种危险的态度——如果有数百万用户在运行该程序,那么问题发生的可能性往往是不可避免的。
  • 你们都提出了正确的观点:根据条件,可能会出现竞争条件,但可能会因 CanExecute/Execute 差距而产生竞争条件,但会强制将约束检查到 Execute方法并且从不检查 CanExecute 对我来说似乎违反了合同。我会从纯粹的美学基础上争辩说 CanExecute 应该包含您的前提条件检查,并且在程序调用时,整个 CanExecute/Execute 序列应该包含在锁中。我认为这主要是因为在合同上,CanExecute 有责任做出决定,因此得名。
【解决方案3】:

你需要先调用 CanExecute,没有什么说实现 ICommand 的类在他们的 Execute 方法中检查他们的 CanExecute。

【讨论】:

    猜你喜欢
    • 2011-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多