WPF 触屏事件后触发鼠标事件的问题及 DataGrid 误触问题

WPF 触屏事件后触发鼠标事件的问题及 DataGrid 误触问题

目录

一、触屏事件连带触发鼠标事件的问题

二、DataGrid 误触问题及解决方法

独立观察员 2021 年 10 月 10 日

一、触屏事件连带触发鼠标事件的问题

这个是 WPF 已知的问题,网络上也有一些讨论,但是没有一个完美的方法来解决。本文也就是讲解其中的一种方法,亲测可行。

先来说说具体现象:触屏操作时,如果程序里使用了触屏事件(如:PreviewTouchDown、TouchDown、PreviewTouchUp、TouchUp),那么相应地会接着触发鼠标事件(PreviewMouseDown、MouseDown、PreviewMouseUp、MouseUp),这个据说是微软为了在触屏设备上兼容老程序,让这些程序能够接收从触屏事件转换来的鼠标事件,从而能正常工作。

所以,有一个说法是,只使用鼠标事件就行了,比如就单单使用 PreviewMouseDown 事件,或者按钮的话直接使用 Click 事件,或者使用命令(Command),这种方法理论上是可以的,但是实际情况下,有的时候会发现,这样用的话,触屏操作很不灵敏,可能要点好几次才触发。

这个触屏事件提升为鼠标事件的一个表现就是,触屏拖动或者点击,会在屏幕上 “残留” 鼠标,当然,是不可见的,或者表现为一个小星号。所以,从这个角度出发,产生了这样一种方法:点击后将鼠标移开。

这个方法能满足部分场景,比如之前有这样一个问题,在 DataGrid 表格上方有一个 DatePicker 日期选择控件,日期展开后,下拉的悬浮框会遮在表格上,当在下拉的悬浮框中选择日期后下拉框收起,这时却在表格上产生了某个条目的选中效果。针对于这个情况,就可以使用移开鼠标的方案,相关帮助类见下方链接:

https://gitee.com/dlgcy/WPFTemplateLib/blob/master/WpfHelpers/ClickAndTouchHelper2.cs 

aefb10bdb5785f7acb778731f7182ded.png

但是这次我遇到了一个 DataGrid 的误触问题,用移开鼠标的方法无效(也有可能是使用方法和时机不对),所以只能另寻它法。

注意,本文将在上篇文章《WPF DataGrid 通过自定义表头模拟首行固定》的示例程序基础上进行演示,建议先看看那篇文章。下面开始改造。

首先在行样式中添加了两个事件,一个是 PreviewTouchDown,另一个是 PreviewMouseDown:

f2482be353ce7b6cf199bd0b94487ab1.png

触屏点击某一行,会先触发 PreviewTouchDown,然后触发 PreviewMouseDown,然后是行改变事件 SelectionChanged,最后依次是 PreviewTouchUp 和 PreviewMouseUp。带有 Preview 前缀的是隧道事件(可视为在事件前触发),没有的是冒泡事件(可视为在事件后触发,此处省略)。

那么如何去除触屏事件后连带引发鼠标事件的影响呢?通过在网络上苦苦搜索和尝试,在旧版的微软社区找到了一个可行的方法,帖子为《Prevent a WPF application to interpret touch events as mouse events?》(这个链接之后可能会访问不了)。

提问者就是为了解决触屏操作下触发鼠标事件的问题:

c9673c4946c5ad5a013dbfd7db0dbfca.png

然后里面两个人分别给出了他们的解决方法,先来看看第一个:

78569cc6860b0fdb0c63a5e49ed08ee3.png

这个就是本文采纳的方法,代码文字版如下:

public static class PreventTouchToMousePromotion
{public static void Register(FrameworkElement root){root.PreviewMouseDown  = Evaluate;root.PreviewMouseMove  = Evaluate;root.PreviewMouseUp  = Evaluate;}private static void Evaluate(object sender, MouseEventArgs e){//StylusDevice 属性,触屏操作连带触发时不为 null,鼠标触发时为 null;if (e.StylusDevice != null){e.Handled = true; // 如果判断为 由触屏引发,则将事件标记为已处理;}}
}

再顺便看看第二个人的方法(没有去尝试,感兴趣的朋友可以试试):

bc4ffa7918fd4092410738739ba14628.png

二、DataGrid 误触问题及解决方法

上一个部分介绍了去除触屏事件后连带引发鼠标事件影响的方法,也就是通过鼠标事件参数的 StylusDevice 属性来判断是否是由触屏操作引发的(不为 null 则是触屏操作引发),进而进行处理。

然而,本次我实际上是要解决一个 DataGrid 表格在触屏下的误触问题,相关业务逻辑是在行改变事件(转为命令了)中的,本来是没有写 PreviewTouchDown 和 PreviewMouseDown 事件的(就是为了解决误触问题而引入),所以将鼠标事件标记为已处理(e.Handled = true;)的方法不能直接使用,还需要修改。原因是,行改变事件 SelectionChanged 是在 PreviewMouseDown 事件之后触发的,如果在 PreviewMouseDown 中将事件标记为已处理,那么行改变事件也就不会触发了。

首先来看看误触现象吧(动图):

2086c96963b48555958ff2603c09f339.gif

也就是,我在行改变事件中加了个弹窗,询问用户是否要切换条目,如果选是的话,不作任何处理,如果选否的话,恢复之前的选中项。选是的时候不会有误触现象,选否的时候,鼠标操作的话也正常,而如果在弹窗时通过触屏点击了否,然后在界面空白处(这里是在右侧的信息区)触屏点击几下,就会在表格上,在之前点击要切换到的那一行上产生一个鼠标事件,而且没有触屏事件,这个不用怀疑,通过调试打断点很容易观察到。

关于点击几下会触发这个误触,我发现和屏幕支持几点触控有关。比如,公司的触摸屏支持 10 点触控,那么这里就是点击 10 下左右触发;我自己的一个小触摸屏,支持 5 点触控,这边则是在空白处点击 4 下触发。要查看屏幕支持几点触屏,可通过 GitHub 上的一个项目程序 ManipulationDemo 来查看(https://github.com/dotnet-campus/ManipulationDemo):

f7934f93beafa1ddb1b24a0c246956b6.png

言归正传,从误触现象的动图中可以看到,已经能够判断出是否是误触了:

beba88969f38cae1cca9fb4dc0ee7319.png

那么是怎么判断的呢?来看看代码:

private void EventSetter_PreviewTouchDown(object sender, TouchEventArgs e)
{// 真实触摸时会触发 PreviewTouchDown 事件,而误触时(点击弹窗取消后在空白处点击多次会误触表格)则不会(因为那个只触发鼠标事件);_vm.IsRealTouch = true;
}/* 注意:触摸事件之后还会触发鼠标事件 */private void EventSetter_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{//StylusDevice 属性,触屏操作连带触发时不为 null,鼠标触发时为 nullif (e.StylusDevice != null){// 触屏//e.Handled = true;}else{// 鼠标_vm.IsRealTouch = true; // 避免后续判断不正常;}
}

在 ViewModel 中新增了一个标记变量 IsRealTouch,用来记录是真实的触控或者鼠标点击意图,还是误触。真实触摸时会触发 PreviewTouchDown 事件,而误触时(点击弹窗取消后在空白处点击多次会误触表格)则不会(因为那个只触发鼠标事件),所以只要在鼠标事件 PreviewMouseDown 中能够判断出是否是触屏操作连带触发的就行了,而这个问题在前一部分已经解决了。所以,在触摸事件,以及鼠标事件的单纯鼠标触发的情况下,都对 IsRealTouch 赋值为 true 即可。

行改变事件(命令)中还需要给 IsRealTouch 复位,代码如下:

SelectionChangedCmd ??= new RelayCommand(o => IsCanSelectionChanged, o =>
{try{IsCanSelectionChanged = false;var args = o as SelectionChangedEventArgs;EditType = EditTypeEnum.Show;var isOk = MessageBox.Show($" 是否切换?(是否是误触?{!IsRealTouch})", "触屏误触问题演示", MessageBoxButton.YesNo);if (isOk == MessageBoxResult.No){if (SelectedUser != _originUser){SelectedUser = _originUser;}}}catch (Exception ex){Console.WriteLine(ex);}finally{IsRealTouch = false;_originUser = SelectedUser;IsCanSelectionChanged = true;}
});

可以看到,这样就能识别出是否是误触了。这里是演示,在实际使用时,识别到是误触,就可以直接返回而不用弹窗了。

问题解决了,那么原因呢?对于触屏操作产生鼠标事件,这个是微软为了兼容性而导致的,前面也说过了。至于为什么会有个触点残留在原来的位置,而且点击其它地方一定次数就会触发,这个问题我也没找到原因,请知道的朋友不吝赐教。有两个猜测,一是模态弹窗对事件有影响,一是命令对事件有影响,目前没想到怎么验证。

另外,之前说过弹窗点击是的情况下,后续没有误触现象,所以也有理由怀疑是从代码中改变了选中项(已绑定到 DataGrid 的选中项)所以会有这个问题。从代码中改变选中项又会触发行改变事件,所以加了个 IsCanSelectionChanged 来避免重入,当然,加不加这个避免重入的,都有误触现象。有点晕。 

最后奉上源码地址:https://gitee.com/dlgcy/DLGCY_WPFPractice/tree/Blog20211010 ,大家可以帮忙研究研究。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/297016.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

听说,99%的数学家都算不出这道题

全世界只有3.14 % 的人关注了爆炸吧知识著名的数学家毕达哥拉斯曾说:“朋友是你灵魂的倩影,要像220与284一样亲密。”就因为不经意的一句话,引发了一场数群和数学家长达几千年的“斗争”,甚至到现在依然没有结束!无数个…

oracle账号区分大小写吗,实战Oracle 11g用户密码不区分大小写

连接到:Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - ProductionWith the Partitioning, OLAP, Data Mining and Real Application Testing optionsSQL> show  parameter sec_case_sensitive_logonNAME TYPE VAL…

sql 多表多行模糊查询_从零开始学习SQL(五)多表查询

经过之前的学习,现在我们已经对查询有了一定的了解,但是我们目前的所有查询都只能找到在一张表中的数据,但如果我们需要寻找分布在多张表格中的数据时,这种之前的查询就做不到了,这时就需要引入一种新的查询方法&#…

最新.NET MAUI有什么惊喜?

点击蓝字关注我们.NET 6 RC1 现已发布啦,我们为 .NET 多平台应用程序 UI (MAUI) 引入了所有的新布局。这是性能和可靠性的重大变化。我们很高兴我们还增加了一些关于accessibility方面的基于新的SemanticService、字体缩放选项和对Xamarin.Forms 效果的兼容性的功能…

亲一下就搞定的事,绝不花钱解决!

1 好了,你表演吧,球不看了2 “你这个车,至少得100条小鱼干啊” 3 羡慕了4 还…还有这种操作?5 被秀了一脸哈哈哈6 没有什么是一个么么哒解决不了的!你点的每个赞,我都认真当成了喜欢

微软发布了Visual Studio 2022 RC版,并将在11月8日发布正式版

微软今天发布了Visual Studio 2022 最接近正式发布的RC版本,同时宣布在11月8日发布正式版,届时将在线上发布虚拟的发布活动,具体参见:https://devblogs.microsoft.com/visualstudio/join-us-november-8th-for-the-launch-of-visua…

arcgis oracle trace,ArcGIS应用Oracle Spatial特征分析

该文章并不是将Oracle Spatial与ST_Geometry做对比,关于两者的对比,可以参考:http://www.linuxidc.com/Linux/2011-10/45492.htm,这里从数据结构,到性能对比,都描述的很清楚。其实这篇文件就是说明一下在A…

SharePoint Timer Job

首先介绍一下什么是定时器作业,说的再多,也不如一张图说的清楚这两张图应该把我想说的已经表达清楚了,下一步介绍一下如何自定义Timer Job第一步:创建一个类(CustomTimerJob.cs)第二步:引用 usi…

这次使用一个最舒服的姿势插入HttpClient拦截器技能点

码甲哥继续在同程艺龙写一点大前端,今天我们来了解一下如何拦截axios请求/响应?这次我们举一反三,用一个最舒适的姿势插入这个技能点。本文阅读耗时5 minute,行文耗时5 Days。axios是一个基于 promise 的网络请求库,可…

甜蜜助攻!情侣之间,到底能有多甜甜甜甜甜甜甜甜

▲ 点击查看没有一丝丝防备,还有 5 天,七夕就要到了。如何借「物」聊表爱意,大概是最近让很多拥有另一半的人头疼不已的问题。重点是,礼物挑不好,小心七夕就变送命题!女孩子们到底喜欢什么礼物?…

多个查询语句能否一次把结果导出_mysql表中base64格式数据查询

需求:为了避开特殊字符(如:单引号)影响,把某些字段保存为base64格式。SQL语句直接解码base64编码数据,直接查询出原始数据。表中数据如下很不直观,当根据where条件查询时,肉眼不能直接从结果提取到可读信息…

【转帖】Reporting Service rdl报表,在aspx页面显示一张完整的RDL报表

第一次弄RDL报表. 权当自己的一个随手笔记吧.希望能有好的意见或者建议欢迎大家提出来. 一起学习.灰常欢迎.. 第一步,先找出你的Reporting Server 的 URL . 如图: 其中URL 就是ReportingServer 的URL 在新建的aspx页面部署的时候非常重要. 虚拟目录的话,在WIN 7 上…

志愿者招募 | 2021 .NET Conf China

回顾往届 .NET Conf China 活动志愿者团队承担着非常重要的职责参与到活动组织和安排过程的方方面面志愿者的团队协作和专业素养展示出了高度的凝聚力和号召力无私付出和敬业得到了多方的好评今年,我们诚邀更多志愿者加入与助力为 2021年中国 .NET 开发者大会提供志…

数学上最有趣的数,装得了逼,撩得了妹!

全世界只有3.14 % 的人关注了爆炸吧知识一分钟记住走马灯数那些美丽有趣的自然数一定有它存在的意义,就像帅气逼人的超模君依然具有令人羡慕的才华。但是,存在这么一些自然数,例如走马灯数一直被视为无用,一身正气的超模君决定找到…

php运算符优先级题目,详解php运算符优先级

php中,一个运算可能是有多个运算符连接在一起的,我们给其运算的执行决定先后顺序,下面由小编给大家介绍php运算符优先级,希望对需要的朋友有所帮助!在php运算中遵循的规则就是:优先级高的运算符优先执行&am…

阿里开发规范文档_华为阿里等技术专家15年开发经验总结:SSM整合开发实战文档...

前言Spring自2002年诞生至今,已有近20年的历史,虽然几经变迁,但始终在继续发展和精进。Spring目前由Pivotal维护和开发。Pivotal是PaaS(平台即服务)的领导者,也是消息中间件RabbitMQ的缔造者。12306的流量销…

Swift中的区间运算符和半开区间运算符

2019独角兽企业重金招聘Python工程师标准>>> 区间&#xff0c;使用三个点表示&#xff08;a...b&#xff09;&#xff0c;表示从a到b&#xff0c;包含a和b&#xff0c;b要大于a&#xff0c;包含第一个和最后一个 半开区间&#xff0c;&#xff08;a..<b&#xf…

使用 Directory.Build 来消除项目文件中的重复配置

使用 Directory.Build 来消除项目文件中的重复配置Intro如果解决方案里的项目比较多的话&#xff0c;往往会有很多重复的项目属性&#xff0c;通常我们可以使用独立的 props 属性文件来配置公用的属性&#xff0c;而一般的属性文件都需要手动的 Import 到项目文件中&#xff0c…

chromium关闭更新_Win10今年最重磅更新!Win10 2004正式版详尽体验

今年首个Windows 10正式版更新于近日上架MSDN&#xff0c;版本号最终确定为Build 19041.208(v2004)&#xff0c;这是一个RTM版本&#xff0c;也就是送到OEM厂商压盘的正式版本&#xff0c;向用户正式推送的时候不会再有什么功能变化。按照微软的一贯逻辑&#xff0c;上半年更新…

Android网络通信的六种方式示例代码

表1展示了Android SDK中的一些与网络有关的API包名表1. Android SDK 网络包包 描述 API LevelJava.net 提供与联网有关的类&#xff0c;包括流和数据包&#xff0…