WPF Listbox auto scroll while dragging

前端 未结 2 1895
长发绾君心
长发绾君心 2020-12-14 16:16

I have a WPF app that has a ListBox. The drag mechanism is already implemented, but when the list is too long and I want to move an item to a position not visib

2条回答
  •  谎友^
    谎友^ (楼主)
    2020-12-14 16:27

    Based on this I have created an Attached Behavior which can easily be used like this -

    Here is the code for attached behavior -

    /// 
    /// Provides extended support for drag drop operation
    /// 
    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(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(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(child);
                    if (childItem != null)
                    {
                        return childItem;
                    }
                }
            }
    
            return null;
        }
    }
    

提交回复
热议问题