WPF 的命令在快速双击时触发两次

  • 本文关键字:两次 命令 双击 WPF wpf
  • 更新时间 :
  • 英文 :


在生产应用程序中,我们注意到我们的 WPF 按钮在快速双击时触发 ICommand.Execute 方法两次。

现在,在每个命令上,应用程序都会被全屏微调器动画覆盖,从而防止与应用程序进行任何进一步的交互。

这个 github 存储库包含该问题的简约重现。请注意:

  • 当按钮的命令触发时,"IsBusy"标志设置为 true
  • 因此,将显示业务指示器叠加
  • 因此,在 300 毫秒后才能再次按下按钮

但是,特别是在速度较慢的计算机上,当快速双击(非常快,就像游戏快速一样(时,可以在 BusyIndicator 阻止第二次调用的情况下触发命令两次(如果输出显示 2 行"单击"行,则可以看到(。

这对我来说是意外的行为,因为 IsBusy 标志在 UI 线程上立即设置为 true。 为什么第二次点击能够通过? 我希望 IsBusy 绑定在 UI 线程上显示覆盖层,阻止任何进一步的交互?

github 示例还包含 2 种解决方法:

  1. 使用 ICommand.CanExecute 阻止 Execute 处理程序
  2. 使用预览鼠标向下防止双击

我试图了解问题是什么。 您更喜欢哪种解决方法?

诊断

这只是我的猜测,而不是可靠且经过确认的信息,但似乎当您单击鼠标按钮时,命中测试会立即完成,但所有与鼠标相关的事件都只计划引发(使用我假设的Dispatcher(。重要的是,单击的控件是在单击发生时确定的,而不是在完全处理上一次单击(包括可能随之而来的所有 UI 更改(之后确定的。

因此,在您的情况下,即使第一次单击导致显示覆盖(从而阻止(ButtonBusyIndicator,如果您在实际显示BusyIndicator之前设法第二次单击(并且不会立即发生(,Button上的单击事件将被安排引发(这将在显示BusyIndicator后发生(, 导致命令再次执行,即使此时BusyIndicator可能会阻止Button

溶液

如果您的目标是在前一个命令仍在执行时阻止命令执行,那么显而易见的选择是使Command.CanExecute结果取决于IsBusy标志的状态。此外,我什至不会称其为解决方法,而是一种适当的设计

您在这里面对的是一个明确的例子,说明为什么不应该让业务逻辑依赖于 UI。首先,因为渲染在很大程度上取决于机器的处理能力,其次,因为到目前为止,用另一个控件覆盖按钮并不能保证按钮不能被"单击"(例如使用 UI 自动化框架(。

最新更新