.NET MAUI WinUI平台获取ScrollBar实例及判断按压状态的替代方案
.NET MAUI WinUI平台判断ScrollBar是否被按压的替代方案
问题描述
我们在.NET MAUI应用的WinUI平台上,需要判断Microsoft.UI.Xaml.Controls.Primitives.ScrollBar是否被按压。目前的实现是绑定PointerPressed事件,通过遍历PointerRoutedEventArgs中OriginalSource的父元素直到找到ScrollBar来判断;但滚动条滚动时,内容触摸能检测到Move动作,现在想找WinUI平台特定或.NET Maui层面的替代方法来获取ScrollBar实例。
当前实现代码:
// PointerPressed event. private void PointerPressed(object sender, PointerRoutedEventArgs e) { if ((e.OriginalSource is Microsoft.UI.Xaml.Shapes.Rectangle || e.OriginalSource is Microsoft.UI.Xaml.Controls.Grid)) { if (this.IsScrollBarPressed(e.OriginalSource)) { return; } } } private bool IsScrollBarPressed(object touchElement) { DependencyObject parent = VisualTreeHelper.GetParent(touchElement as DependencyObject); while (parent != null) { parent = VisualTreeHelper.GetParent(parent); if (parent is ScrollBar) { return true; } } return false; }
替代方案
方案一:优化现有遍历逻辑
现有遍历逻辑容易漏掉ScrollBar的直接子控件(比如滚动条的滑块Thumb、上下/左右按钮RepeatButton,这些才是按压时的OriginalSource),可以调整遍历逻辑,覆盖这类场景:
private bool IsScrollBarPressed(object touchElement) { DependencyObject current = touchElement as DependencyObject; while (current != null) { // 直接判断当前元素是否是ScrollBar if (current is ScrollBar) { return true; } // 判断父级是否是ScrollBar(覆盖滑块、按钮等子控件的情况) var parent = VisualTreeHelper.GetParent(current); if (parent is ScrollBar) { return true; } current = parent; } return false; }
方案二:直接获取ScrollBar实例并绑定事件
WinUI中可以直接从ScrollViewer的模板里提取ScrollBar,然后绑定它的按压相关事件,直接标记状态:
- 先实现一个VisualTreeHelper的扩展方法,用来查找子元素:
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls.Primitives; using System; public static class DependencyObjectExtensions { public static T FindDescendant<T>(this DependencyObject parent, Func<T, bool> predicate = null) where T : DependencyObject { int childCount = VisualTreeHelper.GetChildrenCount(parent); for (int i = 0; i < childCount; i++) { var child = VisualTreeHelper.GetChild(parent, i); if (child is T target && (predicate == null || predicate(target))) { return target; } var descendant = child.FindDescendant<T>(predicate); if (descendant != null) { return descendant; } } return null; } }
- 获取ScrollBar并绑定事件:
// 假设你的MAUI滚动容器是ScrollView,先拿到WinUI原生的ScrollViewer实例 var mauiScrollView = YourScrollViewControl; var winuiScrollViewer = (Microsoft.UI.Xaml.Controls.ScrollViewer)mauiScrollView.Handler.PlatformView; // 查找垂直/水平滚动条 var verticalScrollBar = winuiScrollViewer.FindDescendant<ScrollBar>(sb => sb.Orientation == Microsoft.UI.Xaml.Controls.Orientation.Vertical); var horizontalScrollBar = winuiScrollViewer.FindDescendant<ScrollBar>(sb => sb.Orientation == Microsoft.UI.Xaml.Controls.Orientation.Horizontal); // 标记滚动条按压状态的变量 private bool _isVerticalScrollBarPressed; private bool _isHorizontalScrollBarPressed; // 绑定事件 if (verticalScrollBar != null) { verticalScrollBar.PointerPressed += (s, e) => _isVerticalScrollBarPressed = true; verticalScrollBar.PointerReleased += (s, e) => _isVerticalScrollBarPressed = false; verticalScrollBar.PointerCanceled += (s, e) => _isVerticalScrollBarPressed = false; } if (horizontalScrollBar != null) { horizontalScrollBar.PointerPressed += (s, e) => _isHorizontalScrollBarPressed = true; horizontalScrollBar.PointerReleased += (s, e) => _isHorizontalScrollBarPressed = false; horizontalScrollBar.PointerCanceled += (s, e) => _isHorizontalScrollBarPressed = false; }
之后就可以直接通过_isVerticalScrollBarPressed和_isHorizontalScrollBarPressed变量判断滚动条是否被按压,无需再遍历父元素。
方案三:MAUI层面间接判断(适合非精确场景)
如果不需要直接操作ScrollBar实例,可以结合MAUIScrollView的Scrolled事件和触摸事件的时机来间接判断:
- 记录触摸开始的时间戳
- 在
Scrolled事件触发时,对比时间差,如果触摸后立即触发滚动,大概率是按压了ScrollBar - 但这种方法无法区分是拖动滚动条还是滑动内容,适合对精度要求不高的场景
内容的提问来源于stack exchange,提问作者Diwakar Venkatesan
相关产品推荐
相关产品推荐

