title author date CreateTime categories
WPF 高性能笔
lindexi
2019-1-28 14:21:5 +0800
2018-2-13 17:23:3 +0800
笔迹 WPF

本文告诉大家WPF的INK的实现,和如何做一个高性能的笔。

高性能的笔迹在 WPF 包含两个部分,一个是就是输入,第二个就是渲染。

如果需要经过路由事件才收到输入,如果有人在路由事件做了很多需要很长事件的代码,那么等待用户的路由事件就会使用很长的时间。

如果需要等待主界面的布局也就是如果主线程卡住了,就需要等待主线程才可以渲染。

所以按照原来的元素的输入渲染是无法做到高性能的,那么 WPF 的笔迹是如何做到很快?这里需要用到两个科技,一个就是输入使用 StylusPlugin 一个就是使用另一个 UI 线程解决渲染的速度。

这里说的另一个 UI 线程解决渲染速度而不是使用另一个渲染线程是因为在 WPF 是分开主线程渲染线程,具体请看 WPF 渲染原理。

为什么 Stylusplugin 可以做到高性能?

这个需要从触摸开始讲。在我的另一篇博客有告诉大家从触摸到事件,在 WPF 是通过触摸线程拿到触摸信息。

在触摸线程获取触摸消息的时候,会根据收到的触摸消息转发不同的方法。

在转发的过程,在 WPF 会通过 StylusPlugins 里静态字典,存放用户设置的类。在触摸线程会通过判断触摸点时候在命中对应的元素矩形区判断当前时候命中到这个元素。这里判断命中测试和 WPF 说的命中测试使用的不是同相同的方法,这里只是简单获取每个界面元素的矩形,然后用触摸的点坐标判断是否在这个矩形内,也就是不判断元素是否被其他的元素挡住。所以这个判断方法不需要遍历视觉树,性能相对很高。

这是就为什么使用 StylusPlugin 的获取输入性能比较快。因为这个过程是从触摸线程拿到的,而且触摸线程在执行 StylusPlugin 后才执行到路由事件的代码,使用 StylusPlugin 的速度会比路由事件快很多,加上路由事件需要做命中测试,可能用户会在路由事件做很多事件。而 Stylusplugin 只是从触摸线程拿到,完全不需要等用户在路由事件代码。

下面就是在触摸线程调用 Stylusplugin 的代码

在使用渲染这里用另一个线程做 UI 线程,在 WPF 不是只有主线程可以做 UI 线程,这里的 UI 线程和渲染线程是不相同,因为渲染线程是收集 UI 线程发过来的数据然后才进行渲染。

这里通过 VisualHost 的方法创建一个 UI 线程,在这个线程计算笔迹,然后添加到这个线程的元素,通过这个方式可以在主线程做其他代码的时候还可以快速在用户触摸的时候告诉渲染线程。

在 WPF 的 笔迹是没有额外创建一个线程作为另一个 UI 线程,而是直接将触摸收集线程作为另一个 UI 线程。当然这个方法如果没用好可能就会在用户多个手指书写时无法做到足够高的速度。

如果要做高性能的笔必须要了解 WPF 的触摸和渲染原理,具体请看WPF 渲染原理WPF 触摸到事件

于是下面告诉大家如何做出一个高性能的笔。

本文主要告诉大家如何继承 StylusPlugIn 来做高性能的笔。需要知道 StylusPlugIn 提供了底层的触摸事件,这个事件从 Wisp 进程获得数据然后直接给框架,然后给 UIElement 所以继承StylusPlugIn可以拿到比路由事件更快。

为什么说 StylusPlugIn 拿到比 路由事件更快,这需要了解一下 lnk 的底层。

如果直接从 StylusDown 事件拿到,那么这个事件是经过 WispLogic 和 StylusLogic 处理之后的值才会传给 Stylus.StylusDownEvent ,然后使用路由事件的方式,先经过隧道然后冒泡才到 UIElement ,如果有人在到 UIElement 之前写了代码,或者主线程做了其他不清真的(while xx)那么用户触摸到 UIElement 收到消息就过去很久。

那么StylusPlugIn为什么会比较快,原因是 StylusPlugIn 没有经过那么多处理,也没有经过隧道,而且他可能还不在主线程,不管主线程被写了多少代码,他这个线程都不会被影响。调用的线程级别是输入,除非主线程真的占用整个CPU,不然主线程的代码对这个线程影响很小。

因为 StylusPlugIn 是从 StylusInput 修改来的,所有的 UIElement 都有 StylusPlugIns 属性,但是这个属性是只有继承 UIElement 的类才可以拿到。从 StylusPlugIn 拿到的数据就是系统拿到的 xy 点和触摸压力,还有触摸宽度。但是这里的宽度是需要反射才可以拿到,不是所有的触摸屏都可以报告触摸宽度。

如果需要加入到 StylusPlugIn 首先需要继承 StylusPlugIn

先创建一个类 TtkSwvlypxm 继承 StylusPlugIn ,那么可以通过重写获得

  • OnAdded 被添加时

  • OnRemoved

  • OnStylusEnter 触摸时

  • OnStylusLeave

  • OnStylusDown

  • OnStylusMove

  • OnStylusUp

  • OnStylusDownProcessed 可以判断是否失焦

  • OnStylusUpProcessed

那么在这里类,几乎可以不写代码就获得触摸事件,从这里获得触摸事件比路由会快,因为这里是 rawStylusInput ,没有处理的事件,可以获得触摸宽度和触摸的元素。

那么如何加入这个类?

使用 InkPresenter 创建一个类,这个类用来显示笔迹,之后需要在添加 InkPresenter 的类 上添加事件

例如 SlwqntthSpeswbrj 添加了 InkPresenter ,那么需要使用下面的代码

            var dynamicRenderer = new TtkSwvlypxm();

            dynamicRenderer.Enabled = true;

            SlwqntthSpeswbrj.StylusPlugIns.Add(dynamicRenderer);

这样尝试在触摸时就可以获得触摸事件,因为获得事件比较快,所以性能比较高。

其他的代码因为在公司使用,所以我就不写下来

只要获得了触摸事件,要画出来是很简单。

如果支持多指,其实只需要多创建 TtkSwvlypxm 就可以支持多指

可能存在的问题,刚才有附加的代码 StylusPlugIns.Add ,实际上 StylusPlugIns 是 UIElement 的保护,所以需要写一个函数把这个属性给外面。

如果需要移除,那么请设置dynamicRenderer.Enabled = false; 直接移除会出现直接退出

那么使用 StylusPlugIn 的作用除了做高性能的笔之外还有什么作用?实际上可以看到这个方法可以用来过滤输入,因为他在路由事件之前,而且可以修改点,所以用它来修改过滤。

自己定义的 StylusPlugIn 实际上作为笔迹还是存在很多坑,所以一般都是继承 DynamicRenderer ,这个类对输入做了很多处理,当然也存在一些坑。

参见:Intercepting Input from the Stylus

WPF 渲染原理

WPF 触摸到事件

其他自己写的笔迹算法

2019-1-28-WPF-高性能笔的更多相关文章

  1. WPF 高性能笔

    原文:WPF 高性能笔 本文告诉大家WPF的INK的实现,和如何做一个高性能的笔. 高性能的笔迹在 WPF 包含两个部分,一个是就是输入,第二个就是渲染. 如果需要经过路由事件才收到输入,如果有人在路 ...

  2. 「FFT」题单(upd 2019.4.28)

    持续更新(last upd 2019.4.28) ZJOI2014 力 [题目链接] 解法 对原式进行转换,然后卷积FFT套上去求解就可以了. 推导过程简洁版: \[F_i=\sum_{j<i} ...

  3. Alpha冲刺(5/10)——2019.4.28

    所属课程 软件工程1916|W(福州大学) 作业要求 Alpha冲刺(5/10)--2019.4.28 团队名称 待就业六人组 1.团队信息 团队名称:待就业六人组 团队描述:同舟共济扬帆起,乘风破浪 ...

  4. 2019.3.28&2019.3.30考试

    2019.3.28 : 肥肠爆芡,因为这场考试的题太屑了,所以我咕咕了 Upd on 2019.3.30 压进来一篇(因为都没啥意义) 2019.3.30 : 全机房读错题+没有大样例=T2全体爆炸 ...

  5. 2019.2.28&2019.3.1 考试

    因为没A/改几道题,就一起写了 题目在LOJ上都能找到 2019.2.28 100+20+12 前两个小时一直在睡觉+想题也没思路,我太菜了 T1 洗衣服 分开处理出洗衣服和烘干的时间,然后一边正着排 ...

  6. 梦想MxWeb3D协同设计平台 2019.02.28更新

    梦想MxWeb3D协同设计平台 2019.02.28更新 SDK开发包下载地址: http://www.mxdraw.com/ndetail_10130.html 在线演示网址: http://www ...

  7. Beta冲刺(7/7)——2019.5.28

    所属课程 软件工程1916|W(福州大学) 作业要求 Beta冲刺(7/7)--2019.5.28 团队名称 待就业六人组 1.团队信息 团队名称:待就业六人组 团队描述:同舟共济扬帆起,乘风破浪万里 ...

  8. AI2(App Inventor 2)离线版服务器(2019.04.28更新)

    我们的目标:搭建一个本地多用户的App Inventor 2 服务器   演示: http://ai2.fsyz.net  [旧 win]     http://ai2n.fsyz.net [新 Ce ...

  9. Cheatsheet: 2018 11.01 ~ 2019 02.28

    Golang FromXToGo micro - A microservice toolkit Other Easy parsing of Excel spreadsheet format with ...

  10. 项目Beta冲刺(6/7)(追光的人)(2019.5.28)

    所属课程 软件工程1916 作业要求 Beta冲刺博客汇总 团队名称 追光的人 作业目标 描述Beta冲刺每日的scrum和PM报告两部分 队员学号 队员博客 221600219 小墨 https:/ ...

随机推荐

  1. 8VC Venture Cup 2017 - Elimination Round - C

    题目链接:http://codeforces.com/contest/755/problem/C 题意:PolandBall 生活在一个森林模型的环境中,定义森林由若干树组成,定义树为K个点,K-1条 ...

  2. Linux防火墙--iptables--白名单配置

    1.服务器22端口和1521端口开通给指定IP [root@node2 sysconfig]# iptables -t filter -nL INPUT Chain INPUT (policy ACC ...

  3. 【学术篇】bzoj2440 [中山市选2011]完全平方数

    -题目の传送门- 题目大意: 找到第k个无平方因子数. 看到数据范围很大, 我们要采用比\(O(n)\)还要小的做法. 考虑如果前\(x\)个数中有\(k-1\)个无平方因子数, 而前\(x+1\)个 ...

  4. Sass Maps的函数-map-keys($map)

    map-keys($map) 函数将会返回 $map 中的所有 key.这些值赋予给一个变量,那他就是一个列表.如: map-keys($social-colors); 其返回的值为: "d ...

  5. PHP: 双层 for循环的执行过程

    先看代码 <?php for ($i = 0; $i<3; $i++) { for ($x = 0; $x<3; $x++) { // code... } } ?> 看下它的执 ...

  6. java api 调用es集群(1.7版本)

    public static void main(String[] args) { Settings settings = ImmutableSettings.settingsBuilder() // ...

  7. Autoit3域用户的登陆统计

    #include <ACN_NET.au3> If @OSArch="X86" Then $fileURL=@CommonFilesDir & "\S ...

  8. 如何使用Keka for Mac提取受密码保护的文件?用Keka提取文件的格式

    如何使用Keka for Mac提取受密码保护的文件?keka Mac是很多人喜欢的压缩解压工具,以小巧,使用简单,界面简洁受到很多Mac用户的喜欢,你还可以使用它提取文件,下面我们就来介绍一下关于用 ...

  9. mobx学习笔记02——mobx基础语法(class)

    新的语法可能不被浏览器支持,可以使用babel转换为浏览器支持的代码格式: 为什么要定义class? js是一门面向对象的编程语言.需要利用类来复用代码,提高编程效率. 需要什么样的class能力? ...

  10. 4412 i2c驱动

    1.Linux主机驱动和外设驱动分离思想 外设驱动→API→主机驱动→板机逻辑--具体的i2c设备(camera,ts,eeprom等等) 2.主机驱动 根据控制器硬件手册,操作具体的寄存器,产生波形 ...