【问题标题】:Why do all WPF Touch events now only fire as MouseEvents?为什么现在所有 WPF 触摸事件都只作为 MouseEvents 触发?
【发布时间】:2020-03-02 18:40:17
【问题描述】:

是否有某种晦涩的方法可以让我一次性全局(意外)禁用整个 WPF 应用程序中的所有 Touch 事件——以便将它们“提升”为鼠标事件?是否有一些全局 WPF 标志将它们关闭。如果是这样,谁能告诉我它可能是什么?

详细说明:

我有一个在 MS Surface 上运行的 WPF 桌面应用程序 (.NET Core 3.1)。近 2 年来,它在触控和鼠标处理程序上都运行良好;如果用户用鼠标单击,鼠标处理程序被调用。如果用户用手指触摸,则调用 ManipulationEvent(或 TouchEvent)处理程序。

但最近我看到了奇怪的行为,我终于意识到每个触摸操作事件都在到达我的任何触摸/操作处理程序之前被“提升”为鼠标事件。

例如,这是我在其中一个视图中应用于 Path 对象的样式:

<Style x:Key="ShapeDragPathStyle" TargetType="{x:Type Path}">
    <Setter      Property="Cursor"           Value="Hand" />
    <EventSetter Event="MouseLeftButtonDown" Handler="Shape_OnLeftButtonDown" />
    <EventSetter Event="MouseMove"           Handler="Shape_OnMouseMove" />
    <EventSetter Event="MouseLeftButtonUp"   Handler="Shape_OnMouseLeftButtonUp" />
    <EventSetter Event="TouchDown"           Handler="Shape_OnTouchDown" />
</Style>

现在,如果我放下手指并拖动具有这种样式的路径,将调用 OnLeftButtonDown 处理程序。 TouchDown 处理程序永远不会。

为了完整起见,这里列出了我在 XAML 的不同位置声明了处理程序并且我已经使用了很长时间的所有触摸事件。

ManipulationStarting
ManipulationStarted 
ManipulationDelta
ManipulationCompleted
TouchUp
TouchDown
PreviewTouchDown

不再调用这些处理程序。我真的去给它们的每个处理程序设置了断点,不管它们在哪里。我是否有IsManipulationEnabled="True" 并不重要。鼠标等效项总是被调用。

这似乎也不是 Windows 设置中的内容。我已经验证它发生在多台 MS Surface 机器上,而且它似乎只发生在我的应用程序中;我创建了一个简单的 .NET Core 3.1 测试应用程序并添加了一个 ManipulationStarting 处理程序,效果很好。

我应该寻找什么想法?

(我敢肯定当我发现时我会感到很愚蠢,但我已经有这种感觉了......)

【问题讨论】:

    标签: wpf touch touch-event


    【解决方案1】:

    回答我自己的问题,因为我通过比较测试应用程序与我的应用程序的触摸处理调用堆栈猜到了原因。这个问题似乎很模糊,但我可以看到其他人有这个问题,所以这就是发生的事情:

    简而言之,罪魁祸首是System.Management.ManagementEventWatcher

    我希望在插入 USB 设备时通知我的应用。因此我创建了一个 ManagementEventWatcher 来监视此类事件

    Watcher = new ManagementEventWatcher(
        new ManagementScope("root\\CIMV2"),
        new WqlEventQuery()
        {
            EventClassName = "Win32_DeviceChangeEvent",
            Condition      = "EventType = 2 OR EventType = 3",
        });
    
    Watcher.EventArrived += (sender, args) => { DeviceChanged?.Invoke(this, true); };
    
    Watcher.Start();  // THIS WAS THE PROBLEM
    

    在主 UI 线程上调用 Start() 似乎会改变主线程处理窗口消息的方式。当我这样做时,整个调用堆栈看起来不同。在任何东西到达我的代码之前,传入的触摸消息都会直接发送到鼠标处理程序。

    当我注释掉对Start() 的调用时,所有的触摸处理程序都会再次被调用。

    所以我尝试在后台线程上调用Start()

    Task.Run(() => Watcher.Start());
    

    现在一切正常。我不确定这是最终的答案——我什至可能想创建自己的专用线程以避免弄乱任何线程池线程——但显然就是这样。

    所以看起来ManagementEventWatcher 是 UI 线程最好不要使用的东西,至少在 WPF 中是这样

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多