1. 程式人生 > >WPF觸屏Touch事件在嵌套控件中的響應問題

WPF觸屏Touch事件在嵌套控件中的響應問題

容器 tool 分享 原來 控件 區域 fonts 嵌套 記錄

原文:WPF觸屏Touch事件在嵌套控件中的響應問題

前幾天遇到個touch事件的坑,記錄下來以增強理解。

具體是 想把一個listview嵌套到另一個listview,這時候如果list view(子listview)的內容過多超過容器高度,它是不會出現滾動條壓縮內容區域的,反而會將滾動區域轉移到外面的list view(父listview),這個無可爭議,但這個問題開始沒留意,為待會的坑埋下伏筆。技術分享圖片

因為 然後就是設置鼠標滾輪。

首先我使用了MouseWheel事件,奇怪的是它明明是個路由事件,然而listview似乎做了處理,沒有冒泡到父級。

於是我改寫PreviewMouseWheel事件,吧從父級傳過來的時間再冒泡回去。

在子類的listview中,我在滾動事件裏寫了個向上傳遞的觸發事件:

 private void BodyList_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
        {
            var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
            eventArg.RoutedEvent = UIElement.MouseWheelEvent;
            eventArg.Source 
= sender; BodyList.RaiseEvent(eventArg); }

這樣我就能實現當鼠標焦點在子listview時,能觸發父級的滾動事件

這時候為了觸摸屏操作,我如是寫了touchdown .touchmove touchup 三個事件,可是,當手勢在子listview做滑動操作的時候,父級不滑動。

即使我完全偽造一個source為上級的touch事件,父級仍然巋然不動,如圖:

      private void UIElement_OnTouchMove(object sender, TouchEventArgs e)
        {
            
            
var eventArg = new TouchEventArgs(e.TouchDevice,e.Timestamp); eventArg.RoutedEvent = UIElement.TouchMoveEvent; eventArg.Source = HAHAListBox; (sender as UIElement).TryFindParent<ListBox>().RaiseEvent(e); e.Handled = true; }

於是我開始找原因,touch事件同樣是路由事件,於MouseWheel不同的是,我可以在父listview觸發它。

那麽是什麽原因呢,通過可視化樹工具,可以發現,在嵌套的listview中實際上嵌套了兩個scrollview, 當touch事件在 子listview中觸發時,實際上事件被子級中的scrollview吸收了。但是為何偽造後仍然無法反應?

技術分享圖片

那是由於touch事件是一個特殊的事件,至少有別於滾輪事件,控件需要對手勢在觸摸屏上的坐標做出響應,兩個相互嵌套的滑動控件,無法對同一手勢坐標做出反應,否則他們之間的相對位置就會發生改變,也就是說兩個scrollview不能同時依賴一個手勢源,只有最上層的scrollview才能響應目標源。

不知道微軟為何這麽設定,至少我的理解是這樣的

由於開始的設置,子listview中的scrollview永遠不會有效果。因此容易被忽略

所以我們只要重寫底層listview的template就好了,把原來包裹ItemsPresenter的Scrollview控件給刪掉

touch事件就能被父一級的listview觸發了!

希望這個繞坑的經歷能幫助到大家,謝謝!

WPF觸屏Touch事件在嵌套控件中的響應問題