[WPF]使用附加属性处理 ScrollViewer 的滚动轮劫持问题

之前写过一篇博客 关于 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();
              }
          };
    }

}

处理不够优雅,但将就着用吧。

参考

[UWP]附加属性1:概述

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

posted @ 2020-06-08 14:32  dino.c  阅读(276)  评论(8编辑  收藏