WPF之坑——surface触控失灵之谜

本次又遇到了WPF编写触控程序的一个问题,虽然已解决,但原因确搞不太明白,希望有大神看到这篇文章帮我解答。

在项目中实现了自己定义的icommandsource,因为需要对触控有特殊需求,控件对鼠标与触摸有了各自的事件响应,以下代码是原始touchup事件的处理逻辑。

 1         protected override void OnTouchUp(TouchEventArgs e)
 2         {
 3             if (_deviceId == e.TouchDevice.Id)
 4             {
 5                 ReleaseAllTouchCaptures();
 6                 ReleaseDevice();
 7 
 8                 if (!_isDraging)
 9                 {
10                       RoutedEventArgs rea = new RoutedEventArgs(Button.ClickEvent, this);
11                       RaiseEvent(rea);
12 
13                       if (!rea.Handled && ClickCommand != null)
14                       {
15                           ClickCommand.Execute(ClickCommandParam);
16                       }
17 
18                 }
19 
20                 base.OnTouchUp(e);
21         }        

使用该控件编写界面,触摸点击按钮后弹出其他窗口,这时神奇的事件发生了:

如果使用的是带触控屏的PC上,新弹出的窗口不会自动激活需要新点击1次(貌似问题不大)

但如果程序运行在一台surface上,新弹出的窗口需要点击10次才会被激活,随后其中的控件才会收到事件响应。(PC与Surface均是win10系统,需要点击10次这个数据很准确,已经过反复测试,就像是谁在代码是设置了计数器一样准确)。

发现问题后感觉特别茫然,也没查到太多有关信息,一顿乱试发现了解决方案。改写后的代码如下:

 1         protected override void OnTouchUp(TouchEventArgs e)
 2         {
 3             if (_deviceId == e.TouchDevice.Id)
 4             {
 5                 ReleaseAllTouchCaptures();
 6                 ReleaseDevice();
 7 
 8                 if (!_isDraging)
 9                 {
10                     DelayRaiseClick();
11                 }
12             }
13 
14             base.OnTouchUp(e);
15         }
16 
17         private async void DelayRaiseClick()
18         {
19             await System.Threading.Tasks.Task.Run(() =>
20             {
21                 System.Threading.Thread.Sleep(50);
22             });
23 
24             RoutedEventArgs rea = new RoutedEventArgs(Button.ClickEvent, this);
25             RaiseEvent(rea);
26 
27             if (!rea.Handled && ClickCommand != null)
28             {
29                 ClickCommand.Execute(ClickCommandParam);
30             }
31         }

可以看到,上下代码的唯一区别仅是抛出click事件前异步等待了50ms,但这个变化使得新弹出的窗口可以直接激活,surface与pc上运行效果一致。那么问题就来了,在这异步等待的50ms中发生了什么,我能想到的就是,界面的路由事件可以完整的传递完毕,包括touchup和由触摸引发的mouseup消息。至于为什么消息没有传递完毕就会出问题(把e.Handled置为true可以阻止消息继续传递啊,也没说必须传递完)想不明白,还有,为什么在surface上需要操作10次,这个计数是谁干的,完全没有头续。。。

借用我一个同事的话说,这个解决方案虽然完成了任务,但太恶心了(ps,他也遇到了跟我一样的问题,而具用的是wpf原生按钮,这让这个问题更难理解了)

最后,希望有了解的大神帮我解释这个问题,从而得到不恶心人的解决方法。。

原文地址:https://www.cnblogs.com/GuoRL/p/5944649.html