title
author
date
createtime
categories
wpf 高效能筆
lindexi
2019-11-29 10:20:51 +0800
2018-2-13 17:23:3 +0800
筆跡 wpf
高效能的筆跡在 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 ,那麼可以通過重寫獲得
那麼在這裡類,幾乎可以不寫**就獲得觸控事件,從這裡獲得觸控事件比路由會快,因為這裡是 rawstylusinput ,沒有處理的事件,可以獲得觸控寬度和觸控的元素。
那麼如何加入這個類?
使用 inkpresenter 建立乙個類,這個類用來顯示筆跡,之後需要在新增 inkpresenter 的類 上新增事件
例如 slwqntthspeswbrj 新增了 inkpresenter ,那麼需要使用下面的**
vardynamicrenderer
=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 11 29 WPF 模擬觸控裝置
title author date createtime categories wpf 模擬觸控裝置 lindexi 2019 11 29 08 47 53 0800 2019 5 11 17 2 6 0800 wpf在 wpf 中觸控只是框架的一層,可以通過 模擬觸控 建立乙個類繼承 touchd...
2019 11 29 WPF 從觸控訊息轉觸控事件
title author date createtime categories wpf 從觸控訊息轉觸控事件 lindexi 2019 11 29 08 47 55 0800 2019 05 12 15 12 31 0800 wpf在 wpf 程式可能因為一些坑讓程式觸控失效,如果此時還可以收到系統...
2019 1 28 WPF 高效能筆
title author date createtime categories wpf 高效能筆 lindexi 2019 1 28 14 21 5 0800 2018 2 13 17 23 3 0800 筆跡 wpf 高效能的筆跡在 wpf 包含兩個部分,乙個是就是輸入,第二個就是渲染。如果需要經...