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事件在嵌套控件中的響應問題