使用 ScrollViewer 单击并拖动滚动

2024-01-09

我想允许使用单击并拖动滚动ScrollViewer(即单击ScrollViewer并向上或向下拖动,它会相应滚动)

我有一个StackPanel嵌套在一个ScrollViewer我已经可以滚动了。我相信我在某处看到过这个答案,但我似乎再也找不到了。

这必须仅使用代码来完成。


Look at 此代码来自马特·汉密尔顿 http://matthamilton.net/touchscrolling-for-scrollviewer:

public class TouchScrolling : DependencyObject
{
    public static bool GetIsEnabled(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsEnabledProperty);
    }

    public static void SetIsEnabled(DependencyObject obj, bool value)
    {
        obj.SetValue(IsEnabledProperty, value);
    }

    public bool IsEnabled
    {
        get { return (bool)GetValue(IsEnabledProperty); }
        set { SetValue(IsEnabledProperty, value); }
    }

    public static readonly DependencyProperty IsEnabledProperty =
        DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(TouchScrolling), new UIPropertyMetadata(false, IsEnabledChanged));

    static Dictionary<object, MouseCapture> _captures = new Dictionary<object, MouseCapture>();

    static void IsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var target = d as ScrollViewer;
        if (target == null) return;

        if ((bool)e.NewValue)
        {
            target.Loaded += target_Loaded;
        }
        else
        {
            target_Unloaded(target, new RoutedEventArgs());
        }
    }

    static void target_Unloaded(object sender, RoutedEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine("Target Unloaded");

        var target = sender as ScrollViewer;
        if (target == null) return;

        _captures.Remove(sender);

        target.Loaded -= target_Loaded;
        target.Unloaded -= target_Unloaded;
        target.PreviewMouseLeftButtonDown -= target_PreviewMouseLeftButtonDown;
        target.PreviewMouseMove -= target_PreviewMouseMove;

        target.PreviewMouseLeftButtonUp -= target_PreviewMouseLeftButtonUp;
    }

    static void target_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        var target = sender as ScrollViewer;
        if (target == null) return;

        _captures[sender] = new MouseCapture
        {
            VerticalOffset = target.VerticalOffset,
            Point = e.GetPosition(target),
        };
    }

    static void target_Loaded(object sender, RoutedEventArgs e)
    {
        var target = sender as ScrollViewer;
        if (target == null) return;

        System.Diagnostics.Debug.WriteLine("Target Loaded");

        target.Unloaded += target_Unloaded;
        target.PreviewMouseLeftButtonDown += target_PreviewMouseLeftButtonDown;
        target.PreviewMouseMove += target_PreviewMouseMove;

        target.PreviewMouseLeftButtonUp += target_PreviewMouseLeftButtonUp;
    }

    static void target_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        var target = sender as ScrollViewer;
        if (target == null) return;

        target.ReleaseMouseCapture();
    }

    static void target_PreviewMouseMove(object sender, MouseEventArgs e)
    {
        if (!_captures.ContainsKey(sender)) return;

        if (e.LeftButton != MouseButtonState.Pressed)
        {
            _captures.Remove(sender);
            return;
        }

        var target = sender as ScrollViewer;
        if (target == null) return;

        var capture = _captures[sender];

        var point = e.GetPosition(target);

        var dy = point.Y - capture.Point.Y;
        if (Math.Abs(dy) > 5)
        {
            target.CaptureMouse();
        }

        target.ScrollToVerticalOffset(capture.VerticalOffset - dy);
    }

    internal class MouseCapture
    {
        public Double VerticalOffset { get; set; }
        public Point Point { get; set; }
    }

}

这里有一些怪癖。我注意到当内容显示时,ScrollViewer 实际上正在被加载、卸载和再次加载。

这意味着我不能只是将事件联系起来IsEnabledChanged方法并将它们解开target_Unloaded事件处理程序,因为它们立即被取消挂钩。相反,我必须将它们挂接到 Loaded 事件的处理程序中,而该处理程序又永远不会被取消挂接。

这意味着其中存在某种“内存泄漏”,但我已经准备好接受它。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 ScrollViewer 单击并拖动滚动 的相关文章

随机推荐