[WPF]为旧版本的应用添加触控支持

之前做WPF开发时曾经遇到这样一个需求:为一个基于 .NET Framework 3.5开发的老旧WPF程序添加触控支持,以便于大屏触控展示。

接手之后发现这是一个大坑。

项目最初的时候完全没考虑过软件架构设计,业务逻辑基本都写在后台代码中,经过两代程序员的开发维护(初代开发者已离职,文档这种东西不存在的),主界面cs代码已经有上万行,各种事件注册的非常杂乱。由于是做给政府部门用的,稳定性很重要,修修补补不断的打补丁,程序已经非常难维护了。

而且不像最新.net框架下的WPF以及UWP开发中,我们有Pointer开头的系列事件可以统一处理鼠标点击和触控。在基于.net框架 4.7以下版本构建的WPF应用里,鼠标点击和触控是独立的,需要分别处理。

这里有一点需要说明:在单点电阻式触控屏(除了ATM机之类的特殊用途,基本要被淘汰掉了)下,系统对单点触控的处理是模拟的鼠标操作,这种情况下即使不处理触控事件,程序也可以正常运行,需要处理触控事件特指的是支持多点触控的电容式触摸屏。

当时我接手的WPF应用之前是完全没有做过触控事件处理的,我粗略的查找统计了一下,需要处理的按钮点击事件大概有上千个,如果手动处理,将是非常难以接受的重复工作,另外修改后的应用程序也必须完整走一遍测试流程,以防带来灾难性BUG。

那么有没有一种简单的方法可以快速处理呢?

我们知道WPF开发中,所有的用户交互事件都是路由事件,其中带有Preview前缀的为隧道路由事件,不带前缀的为冒泡路由事件。其区别是:隧道路由事件由根元素传递到触发事件的元素,而冒泡路由事件传递方向正好相反。那么,尽管程序中需要处理触控事件的地方很多,但是我们都可以在应用顶层元素中通过冒泡路由事件拦截到。是不是可以利用这一点做文章呢?

我的想法是这样的:由于应用已经处理了鼠标交互事件,那我们完全可以将应用的触控事件转发给鼠标交互事件的Handler去处理,这样就避免了我们做机械的重复操作。

具体处理步骤如下:

  1. 在应用窗口的顶级元素(可视化树的根节点)上添加触控事件处理程序,捕获应用内部触控事件;

    this.AddHandler(TouchUpEvent, new RoutedEventHandler(GetTouchUp));
    this.AddHandler(TouchDownEvent, new RoutedEventHandler(GetTouchDown));
  2. 获取引发事件的源控件(原本想通过e.OriginalSource获取,但测试中发现获取的有错误,所以用UIElement类中的InputHitTest方法传入触控点坐标,获取到引发事件的源控件);
    TouchEventArgs te = (TouchEventArgs)e;
    Point p = te.GetTouchPoint(this).Position;//这里是获取触控点相对某个界面元素的坐标
    UIElement uiControl = (UIElement)this.InputHitTest(p);
  3. 触发源控件的鼠标事件(在TouchUp中还同时触发了Button类的Click事件,用于处理按钮的点击事件);
    MouseButtonEventArgs args = new MouseButtonEventArgs(Mouse.PrimaryDevice,te.Timestamp,MouseButton.Left);
    args.RoutedEvent = MouseDownEvent;
    uiControl.RaiseEvent(args);

完整的事件处理代码如下:

        this.AddHandler(TouchUpEvent, new RoutedEventHandler(GetTouchUp));
        this.AddHandler(TouchDownEvent, new RoutedEventHandler(GetTouchDown));
        private void GetTouchDown(object sender, RoutedEventArgs e)
        {
            TouchEventArgs te = (TouchEventArgs)e;
            Point p = te.GetTouchPoint(this).Position;
            UIElement uiControl = (UIElement)this.InputHitTest(p);
            MouseButtonEventArgs args = new MouseButtonEventArgs(Mouse.PrimaryDevice, te.Timestamp, MouseButton.Left);
            args.RoutedEvent = MouseDownEvent;
            uiControl.RaiseEvent(args);
        }
        private void GetTouchUp(object sender, RoutedEventArgs e)
        {
            TouchEventArgs te = (TouchEventArgs)e;
            Point p = te.GetTouchPoint(this).Position;
            UIElement uiControl = (UIElement)this.InputHitTest(p);
            MouseButtonEventArgs args = new MouseButtonEventArgs(Mouse.PrimaryDevice, te.Timestamp, MouseButton.Left);
            args.RoutedEvent = MouseUpEvent;
            uiControl.RaiseEvent(args);
            uiControl.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));
        }

要说明的一点是,我这里的处理是不完善的,仅仅处理了常见的点击操作。譬如鼠标右键(合理的触控事件应该是长按界面元素一段时间后触发),鼠标移动,滚轮操作都没有做处理,这些也是可以通过类似的方法转换为合适的触控事件触发的。

结尾

今天文章里所述的内容其实已经是很久以前的东西了,我现在的主要工作方向远离WPF开发很久了,突然翻相关的旧文件想起来,所以才有了这篇文章。好记性不如烂笔头,知识不用总有忘的一天,不如写出来贡献给需要的人,谢谢大家!

原文地址:https://www.cnblogs.com/hhchaos/p/9986647.html

时间: 2024-10-04 07:59:20

[WPF]为旧版本的应用添加触控支持的相关文章

【WPF学习】第十八章 多点触控输入

多点触控(multi-touch)是通过触摸屏幕与应用程序进行交互的一种方式.多点触控输入和更传统的基于笔(pen-based)的输入的区别是多点触控识别手势(gesture)——用户可移动多根手指以执行常见操作的特殊方式.例如,在触摸屏上放置两根手指并同时移动他们,这通常意味着“放大",而以一根手指为支点转动另一根手指意味着"旋转".并且因为用户直接在应用程序窗口中进行这些手势,所以每个手势自然会被连接到某个特定的对象.例如,简单的具有多点触控功能的应用程序,可能会在虚拟桌

【Cocos2D-X 学习笔记】为精灵添加单点触控

由于Cocos2d-x处于新学的阶段,因此最近也无法进行系统地更新,只会选择一些典型的Demo贴上来,一来是与大家分享,而来也可以作为以后回顾时的参考. 今天介绍一下Cocos2d-x的触摸事件处理,了解Android开发的朋友们知道,Android里会用一个OnClickListener()进行事件监听,而在J2SE中也会有Event类实现专门的监听处理.在Cocos2d-x中,因为是游戏引擎,用户在玩游戏时总是要通过屏幕与游戏进行交互,可想而知触摸事件是主要处理的事件.这里主要讲一下如何为精

bbframework入门之路【五】触控绑定

[正文] 前面我们介绍了如何在bbframework项目中创建我们自己的模块,也在场景里面添加了精灵节点,但是讲到编程就少不了要说到事件.因为我们是做手机游戏,而现在的手机又普遍都是大屏的智能触控手机,所以我们游戏涉及最多的当属触控操作了.今天我们便来简单介绍下bbframework的触控,帮助我们实现游戏的交互操作. 接着上一次的内容,我们在Layer层上面放置了两个节点,代码如下: ---------------------- -- 结点渲染 ---------------------- -

关于android多点触控

最近项目需要一个多点触控缩放的功能.然后上网查了下资料 总结一下: 首先android sdk版本很重要,比如你在AndroidManifest.xml中指定android:minSdkVersion="4"  并且建工程的时候选的是android 2.2就表示你的应用兼容android1.6~android2.2 之间的版本.但是多点触控的API在1.6~~2,1~~,2,2~~三个版本中都是不一样的.比如android2.2中onTouchEvent(MotionEvent eve

ActiveReports 6:如何升级旧版本的项目

如果现在的项目使用的是ActiveReports for .NET 3.0,那么有两种升级方式: 一是使用ActiveReports 6.0附带的转换工具(参见下面"升级ActiveReports for .NET 1.0 或2.0项目"): 二是在Visual Studio中打开工程,用新版本的DLL替换掉旧版本的DLL引用,并且修改代码的编译错误. 替换工程的DLL引用 在Visual Studio中打开需要升级的报表工程. 在解决方案资源管理器中,点击"显示所有文件&q

第二章-第二题(每人自己建立一个HelloWorld项目,练习使用git的add/commit/push/pull/fetch/clone等基本命令。比较项目的新旧版本的差别。)--by侯伟婷

第二题:每人自己建立一个HelloWorld项目,练习使用git的add/commit/push/pull/fetch/clone等基本命令.比较项目的新旧版本的差别. 下面我将自己的练习结果和个人感受记录如下: 第一步:安装Git,设置自己的账号和邮箱,参见Git教程-廖雪峰的官方网站,网址如下参考资料1所示. 第二步:在Git中新建repository,名叫HelloWorld,并进行初始化,如图所示. 第三步:在HelloWorld版本库中新建了helloWorld.txt文件,用以练习G

vue模拟后台数据,请求本地数据的配置(旧版本dev-server.js,新版本webpack.dev.conf.js)

最近学习一个vue-cli的项目,需要与后台进行数据交互,这里使用本地json数据来模仿后台数据交互流程.然而发现build文件夹下没有dev-server.js文件了,因为新版本的vue-webpack-template 中已经去掉了dev-server.js,取而代之的是webpack.dev.conf.js文件,所以可以在webpack.dev.conf.js里配置本地访问. 对比旧版本的build文件夹,新版本的build下少了dev-server.js和dev-client.js 旧版

一个diff工具,用于判断两个目录下所有的改动(比较新旧版本文件夹)

需求: 编写一个diff工具,用于判断两个目录下所有的改动 详细介绍: 有A和B两个目录,目录所在位置及层级均不确定 需要以B为基准找出两个目录中所有有改动的文件(文件或内容增加.修改.删除),将有改动的文件放入第三个目录中,层级结构与原目录相同 将所有新增与更新信息记录到更新日志文件中 将删除信息单独记录到删除日志文件中 每次执行diff工具需要生成一个新的以日期命名的目录存放文件 使用场景: 本工具用于软件版本升级时找出两个版本间所有修改过的文件,便于增量替换. 提示:    使用CRC判断

[转帖]InfluxDB 1.2.0安装及新旧版本的注意事项

InfluxDB 1.2.0安装及新旧版本的注意事项 http://haibing.org/245?zwlqby=npztq3 挺好的文章 很好的解决了 上一个文档里面 关于 web admin 的问题 更多好文章见作者电子书集<Linux运维入门指南:生产运维需要掌握的技能> 随着大数据的爆发,系统数量也是直线上升,监控系统,收集系统运行状态成了保障业务正常运行中的重要一个环节. 针对这种产生频率快.带时间标签.测点多.信息量大的数据,时序数据库(Time Series Database,简