PreviewMouseLeftButtonDown 事件在控件外部触摸时偶尔会触发

PreviewMouseLeftButtonDown event occasionally fires when touching outside the control

我在带触摸屏的笔记本电脑上有一个带有 PreviewMouseLeftButtonDown 事件处理程序 运行 的 WPF TextBox。

当我触摸 TextBox 时,事件处理程序按预期触发。但是,如果我随后触摸应用程序中的其他地方,该事件将在 8 或 9 次触摸后触发。似乎 .NET 认为控件已被直接触摸,即使触摸不在 TextBox 控件之上。据我所知,事件处理程序的发送者和鼠标事件参数在合法的 TextBox 触摸和控件外的第 9 次触摸之间没有显示任何可识别的差异。

这可以很容易地在独立应用程序中重现(请参阅下面的代码和步骤):

  1. 触摸一次文本框。应打开一个新的 window 以显示已触发的事件。
  2. 关闭由事件处理程序
  3. 创建的window
  4. 触摸应用程序中非文本框的任何地方 window 9 次。
  5. A window 应该再次打开,这意味着事件已触发。
public MainWindow()
{
    InitializeComponent();            
    MyTextBox.PreviewMouseLeftButtonDown += MyTextBox_PreviewMouseLeftButtonDown;
}

private void MyTextBox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    var win = new Window();
    win.ShowDialog();
}

多方查找找到解决方案

这是一个已知错误(参见 https://github.com/dotnet/wpf/issues/2491)。

解决方法是在事件处理程序的 Dispatcher.BeginInvoke() 调用中执行 ShowDialog() 代码。

可能发生的事情背后的理论是,在事件处理程序window 期间将焦点更改为新的 window 会导致控件继续认为它处于“着陆”状态“ 状态。当进行后续触摸时,WPF 认为它是多点触摸操作的“第二根手指”并创建另一个处理程序。它会这样做,直到所有“十根手指”都被按下。之后,它循环回到第一个处理程序。由于控件仍然认为它正在被触摸,因此当您的“第一根手指”触摸到应用程序上的任何位置时,它就会触发。

这解释了为什么在文本框外部触摸 9 次后事件始终触发,以及为什么在事件处理程序完成后调用 ShowDialog 可以解决问题。