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

时间:2017-07-29 09:47:29

标签: wpf

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

现在,在每个Command上,应用程序都覆盖了全屏微调器动画,阻止了与应用程序的任何进一步交互。

This github repo包含对该问题的简约重复。请注意:

  • 当Button的命令触发时,“IsBusy”标志设置为true
  • 因此,将显示BusyIndi​​cator叠加层
  • 因此,直到300ms
  • 之后才能再次按下按钮

然而,特别是在慢速计算机上,当快速双击(真的很快,就像快速游戏那样)时,可以在没有BusyIndi​​cator阻止第二次调用的情况下触发命令两次(如果输出显示,则可以看到2'紧跟'彼此之后的行'。

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

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

  1. 使用ICommand.CanExecute来阻止执行处理程序
  2. 使用PreviewMouseDown防止双击
  3. 我正在努力了解问题所在。 您更喜欢哪种解决方法?

1 个答案:

答案 0 :(得分:1)

诊断

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

因此,在您的情况下,即使第一次点击导致显示BusyIndicator覆盖(并因此阻止)Button,如果您设法在{{1}之前第二次点击实际显示(并且不会立即发生),BusyIndicator上的click事件将被调度(将在Button显示后发生),导致命令被执行即使在那时BusyIndicator可能会阻止BusyIndicator

解决方案

如果您的目标是阻止命令执行,而前一个命令仍在执行,那么显而易见的选择是使Button结果取决于Command.CanExecute标志的状态。此外,我甚至不称之为解决方法,而是正确的设计

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