代码之家  ›  专栏  ›  技术社区  ›  Artur Carvalho

WPF列表框在拖动时自动滚动

  •  26
  • Artur Carvalho  · 技术社区  · 17 年前

    我有一个WPF应用程序,它有一个 ListBox . 拖动机制已经实现,但是当列表太长并且我想将项目移动到不可见的位置时,我不能。

    例如,屏幕显示10个项目。我有20件东西。如果我想将最后一个项目拖到第一个位置,我必须拖到顶部并放下。向上滚动并再次拖动。

    我怎样才能做这道菜 自动滚动?

    2 回复  |  直到 13 年前
        1
  •  32
  •   Community Mohan Dere    9 年前

    知道了。使用事件 DragOver ListBox ,使用找到的函数 here 得到 scrollviewer

    private void ItemsList_DragOver(object sender, System.Windows.DragEventArgs e)
    {
        ListBox li = sender as ListBox;
        ScrollViewer sv = FindVisualChild<ScrollViewer>(ItemsList);
    
        double tolerance = 10;
        double verticalPos = e.GetPosition(li).Y;
        double offset = 3;
    
        if (verticalPos < tolerance) // Top of visible list?
        {
            sv.ScrollToVerticalOffset(sv.VerticalOffset - offset); //Scroll up.
        }
        else if (verticalPos > li.ActualHeight - tolerance) //Bottom of visible list?
        {
            sv.ScrollToVerticalOffset(sv.VerticalOffset + offset); //Scroll down.    
        }
    }
    
    public static childItem FindVisualChild<childItem>(DependencyObject obj) where childItem : DependencyObject
    {
        // Search immediate children first (breadth-first)
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(obj, i);
    
            if (child != null && child is childItem)
                return (childItem)child;
    
            else
            {
                childItem childOfChild = FindVisualChild<childItem>(child);
    
                if (childOfChild != null)
                    return childOfChild;
            }
        }
    
        return null;
    }
    
        2
  •  19
  •   Nicolas Mandica    6 年前

    基于此,我创建了一个 Attached Behavior 这样很容易使用-

    <ListView
       xmlns:WpfExtensions="clr-namespace:WpfExtensions" 
       WpfExtensions:DragDropExtension.ScrollOnDragDrop="True"
    

    下面是附加行为的代码-

    /// <summary>
    /// Provides extended support for drag drop operation
    /// </summary>
    public static class DragDropExtension
    {
        public static readonly DependencyProperty ScrollOnDragDropProperty =
            DependencyProperty.RegisterAttached("ScrollOnDragDrop",
                typeof(bool),
                typeof(DragDropExtension),
                new PropertyMetadata(false, HandleScrollOnDragDropChanged));
    
        public static bool GetScrollOnDragDrop(DependencyObject element)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }
    
            return (bool)element.GetValue(ScrollOnDragDropProperty);
        }
    
        public static void SetScrollOnDragDrop(DependencyObject element, bool value)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }
    
            element.SetValue(ScrollOnDragDropProperty, value);
        }
    
        private static void HandleScrollOnDragDropChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            FrameworkElement container = d as FrameworkElement;
    
            if (d == null)
            {
                Debug.Fail("Invalid type!");
                return;
            }
    
            Unsubscribe(container);
    
            if (true.Equals(e.NewValue))
            {
                Subscribe(container);
            }
        }
    
        private static void Subscribe(FrameworkElement container)
        {
            container.PreviewDragOver += OnContainerPreviewDragOver;
        }
    
        private static void OnContainerPreviewDragOver(object sender, DragEventArgs e)
        {
            FrameworkElement container = sender as FrameworkElement;
    
            if (container == null)
            {
                return;
            }
    
            ScrollViewer scrollViewer = GetFirstVisualChild<ScrollViewer>(container);
    
            if (scrollViewer == null)
            {
                return;
            }
    
            double tolerance = 60;
            double verticalPos = e.GetPosition(container).Y;
            double offset = 20;
    
            if (verticalPos < tolerance) // Top of visible list? 
            {
                scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - offset); //Scroll up. 
            }
            else if (verticalPos > container.ActualHeight - tolerance) //Bottom of visible list? 
            {
                scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + offset); //Scroll down.     
            }
        }
    
        private static void Unsubscribe(FrameworkElement container)
        {
            container.PreviewDragOver -= OnContainerPreviewDragOver;
        }
    
        private static T GetFirstVisualChild<T>(DependencyObject depObj) where T : DependencyObject
        {
            if (depObj != null)
            {
                for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
                {
                    DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
                    if (child != null && child is T)
                    {
                        return (T)child;
                    }
    
                    T childItem = GetFirstVisualChild<T>(child);
                    if (childItem != null)
                    {
                        return childItem;
                    }
                }
            }
    
            return null;
        }
    }