之前写过一篇博客 关于 ScrollViewer 和滚动轮劫持(scroll-wheel-hijack),里面介绍了 ScrollViewer 的滚动轮劫持问题,以及如果解决。当时的做法是继承 ScrollViewer 并重写 OnMouseWheel,全部代码如下:
public class ExtendedScrollViewer : ScrollViewer
{
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
if (ViewportHeight + VerticalOffset >= ExtentHeight && e.Delta <= 0)
return;
if (VerticalOffset == 0 && e.Delta >= 0)
return;
base.OnMouseWheel(e);
}
}
最近有人提到能不能使用附加属性处理,所以我就试试。暂时发现简单地用附加属性处理,除非查找 VisualTree 上的父节点 ScrollView 并调用它的 LineUp 和 LineDown ,全部代码如下:
public class ScrollViewerService
{
/// <summary>
/// 从指定元素获取 CanScrollOuter 依赖项属性的值。
/// </summary>
/// <param name="obj">从中读取属性值的元素。</param>
/// <returns>从属性存储获取的属性值。</returns>
public static bool GetCanScrollOuter(DependencyObject obj) => (bool)obj.GetValue(CanScrollOuterProperty);
/// <summary>
/// 将 CanScrollOuter 依赖项属性的值设置为指定元素。
/// </summary>
/// <param name="obj">对其设置属性值的元素。</param>
/// <param name="value">要设置的值。</param>
public static void SetCanScrollOuter(DependencyObject obj, bool value) => obj.SetValue(CanScrollOuterProperty, value);
/// <summary>
/// 标识 CanScrollOuter 依赖项属性。
/// </summary>
public static readonly DependencyProperty CanScrollOuterProperty =
DependencyProperty.RegisterAttached("CanScrollOuter", typeof(bool), typeof(ScrollViewerService), new PropertyMetadata(default(bool), OnCanScrollOuterChanged));
private static void OnCanScrollOuterChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
var oldValue = (bool)args.OldValue;
var newValue = (bool)args.NewValue;
if (newValue == false)
return;
var target = obj as ScrollViewer;
target.PreviewMouseWheel += (s, e) =>
{
if (target.ViewportHeight + target.VerticalOffset >= target.ExtentHeight && e.Delta <= 0
|| target.VerticalOffset == 0 && e.Delta >= 0)
{
var parent = target.GetVisualAncestors().OfType<ScrollViewer>().FirstOrDefault();
if (parent == null)
return;
if (e.Delta < 0)
parent.LineDown();
else
parent.LineUp();
}
};
}
}
处理不够优雅,但将就着用吧。
参考
ScrollViewer.OnMouseWheel(MouseWheelEventArgs) Method (System.Windows.Controls) Microsoft Docs
MouseWheelEventArgs.Delta Property (System.Windows.Input) Microsoft Docs
ScrollViewer.ExtentHeight Property (System.Windows.Controls) Microsoft Docs
ScrollViewer.ViewportHeight Property (System.Windows.Controls) Microsoft Docs
ScrollViewer.VerticalOffset Property (System.Windows.Controls) Microsoft Docs