WinUI3中ListView的PointerWheelChanged事件触摸板下不触发
解决WinUI3 ListView触摸板无法触发PointerWheelChanged事件的问题
问题原因
WinUI3中ListView内部默认包含ScrollViewer组件,触摸板的滚动操作会被该ScrollViewer优先拦截处理,导致外层ListView的PointerWheelChanged事件无法触发;而鼠标滚轮操作的事件传递逻辑不同,不会被拦截,因此能正常触发。
解决方案
方案1:使用PreviewPointerWheelChanged事件
PreviewPointerWheelChanged是隧道事件,会在ScrollViewer处理滚动之前触发,能同时捕获鼠标和触摸板的滚轮操作。
XAML代码:
<ListView x:Name="MyListView" PreviewPointerWheelChanged="MyListView_PreviewPointerWheelChanged"> <!-- 列表项内容 --> </ListView>
后台C#代码:
private void MyListView_PreviewPointerWheelChanged(object sender, PointerRoutedEventArgs e) { // 获取滚轮滚动增量 var pointerPoint = e.GetCurrentPoint(MyListView); int wheelDelta = pointerPoint.Properties.MouseWheelDelta; // 处理逻辑:wheelDelta为正表示向上滚动,负表示向下滚动 if (wheelDelta > 0) { // 向上滚动处理 } else { // 向下滚动处理 } // 如果需要阻止ListView默认滚动行为,取消注释下面一行 // e.Handled = true; }
方案2:监听内部ScrollViewer的ViewChanged事件
通过获取ListView内部的ScrollViewer,监听其ViewChanged事件,该事件会在任何滚动操作(鼠标/触摸板)完成后触发,适合需要根据滚动位置做处理的场景。
C#代码:
private void Page_Loaded(object sender, RoutedEventArgs e) { var scrollViewer = GetListViewScrollViewer(MyListView); if (scrollViewer != null) { scrollViewer.ViewChanged += ScrollViewer_ViewChanged; } } private ScrollViewer GetListViewScrollViewer(ListView listView) { if (VisualTreeHelper.GetChildrenCount(listView) == 0) return null; var border = VisualTreeHelper.GetChild(listView, 0) as Border; return border?.Child as ScrollViewer; } private void ScrollViewer_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e) { var scrollViewer = sender as ScrollViewer; if (scrollViewer == null) return; // 获取当前滚动位置,处理逻辑 double verticalOffset = scrollViewer.VerticalOffset; // 根据verticalOffset的变化判断滚动方向等 }
注意事项
- 使用
PreviewPointerWheelChanged时,若不需要ListView的默认滚动行为,需设置e.Handled = true阻止事件继续传递。 - 获取内部ScrollViewer的方法依赖于ListView的默认模板结构,若自定义了ListView模板,需调整获取逻辑。
内容的提问来源于stack exchange,提问作者Hoka Biu
相关产品推荐
相关产品推荐

