WPF Listbox auto scroll while dragging WPF Listbox auto scroll while dragging wpf wpf

WPF Listbox auto scroll while dragging


Got it. Used the event DragOver of the ListBox, used the function found here to get the scrollviewer of the listbox and after that its just a bit of juggling with the Position.

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;}


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

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

Here is the code for attached behavior -

/// <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;    }}