C# 列表框DragDrop自动滚动问题?

C# 列表框DragDrop自动滚动问题?,c#,wpf,C#,Wpf,我已使用以下方法成功地在列表框中实现拖放: Bea Stollnitz-如何在数据绑定项控件之间拖放项: 但是,当列表有滚动条且我位于列表末尾时,在我拖动项目时,列表框不会自动滚动。 我该如何融入这种行为 编辑:当我在列表的底部边界上时,我希望它滚动,以便我可以将其放在较低的项目上?我使用附加属性来实现这一点,该属性增加了在拖动鼠标时,当鼠标移向控件的顶部或底部时滚动控件的功能。以下是附加的属性类:- public class DragDropAttProps { public sta

我已使用以下方法成功地在列表框中实现拖放:

Bea Stollnitz-如何在数据绑定项控件之间拖放项:

但是,当列表有滚动条且我位于列表末尾时,在我拖动项目时,列表框不会自动滚动。
我该如何融入这种行为


编辑:当我在列表的底部边界上时,我希望它滚动,以便我可以将其放在较低的项目上?

我使用附加属性来实现这一点,该属性增加了在拖动鼠标时,当鼠标移向控件的顶部或底部时滚动控件的功能。以下是附加的属性类:-

public class DragDropAttProps
{
    public static readonly DependencyProperty ScrollOnDragDropProperty =
        DependencyProperty.RegisterAttached(
            "ScrollOnDragDrop",
            typeof(bool),
            typeof(DragDropAttProps),
            new PropertyMetadata(false, HandleScrollOnDragDropChanged));

    public static bool GetScrollOnDragDrop(DependencyObject element)
    {
        return (bool)element.GetValue(ScrollOnDragDropProperty);
    }
    public static void SetScrollOnDragDrop(DependencyObject element, bool value)
    {
        element.SetValue(ScrollOnDragDropProperty, value);
    }

    private static void HandleScrollOnDragDropChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var container = d as FrameworkElement;
        if (d == null)
        {
            Debug.Fail("Invalid type!");
        }

        Unsubscribe(container);

        if (true.Equals(e.NewValue))
        {
            Subscribe(container);
        }
    }

    private static void Subscribe(FrameworkElement container)
    {
        container.PreviewDragOver += OnContainerPreviewDragOver;
    }

    private static void Unsubscribe(FrameworkElement container)
    {
        container.PreviewDragOver -= OnContainerPreviewDragOver;
    }

    private static void OnContainerPreviewDragOver(object sender, DragEventArgs e)
    {
        const double Tolerance = 60;
        const double Offset = 20;

        var container = sender as FrameworkElement;
        if (container == null)
        {
            return;
        }

        var scrollViewer = GetFirstVisualChild<ScrollViewer>(container); 
        if (scrollViewer == null)
        {
            return;
        }

        var verticalPos = e.GetPosition(container).Y;

        if (verticalPos < Tolerance)
        {
            // Top of visible list? Scroll up.
            scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - Offset);
        }
        else if (verticalPos > container.ActualHeight - Tolerance) 
        {
            // Bottom of visible list? Scroll down.
            scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + Offset);
        }
    }

    private static T GetFirstVisualChild<T>(DependencyObject depObj) where T : DependencyObject
    {
        if (depObj != null)
        {
            for (var i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
            {
                var child = VisualTreeHelper.GetChild(depObj, i);
                if (child is T)
                {
                    return (T)child;
                }

                var childItem = GetFirstVisualChild<T>(child);
                if (childItem != null)
                {
                    return childItem;
                }
            }
        }

        return null;
    }
}
公共类DragDropAttProps
{
公共静态只读从属属性ScrollOnDragDropProperty=
DependencyProperty.RegisterAttached(
“ScrollOnDragDrop”,
类型(bool),
类型(DragDropAttProps),
新的PropertyMetadata(错误,HandleScrollOnDragDropChanged));
公共静态bool GetScrollOnDragDrop(DependencyObject元素)
{
返回(bool)元素.GetValue(ScrollOnDragDropProperty);
}
公共静态void setCrollondRagdrop(DependencyObject元素,布尔值)
{
SetValue(ScrollOnDragDropProperty,value);
}
私有静态void HandleScrollOnDragDropChanged(DependencyObject d,DependencyPropertyChangedEventArgs e)
{
var container=d作为框架元素;
如果(d==null)
{
调试失败(“无效类型!”);
}
取消订阅(容器);
if(true.Equals(e.NewValue))
{
订阅(容器);
}
}
私有静态void订阅(FrameworkElement容器)
{
container.PreviewDragOver+=OnContainerPreviewDragOver;
}
私有静态无效取消订阅(FrameworkElement容器)
{
container.PreviewDragOver-=OnContainerPreviewDragOver;
}
ContainerPreviewDragover上的私有静态无效(对象发送器、DragEventArgs e)
{
常数双公差=60;
常数双偏移=20;
var container=发送方作为框架元素;
if(容器==null)
{
返回;
}
var scrollViewer=GetFirstVisualChild(容器);
如果(scrollViewer==null)
{
返回;
}
var verticalPos=e.GetPosition(容器).Y;
if(垂直位置<公差)
{
//可见列表的顶部?向上滚动。
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset-Offset);
}
否则如果(垂直位置>容器实际高度-公差)
{
//可见列表的底部?向下滚动。
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset+Offset);
}
}
私有静态T GetFirstVisualChild(DependencyObject depObj),其中T:DependencyObject
{
if(depObj!=null)
{
for(var i=0;i
最后,在控件的XAML上指定附加属性。免责声明:我在TreeView上使用此方法,但它应适用于任何可滚动控件,如列表框:-

<UserControl xmlns:attProps="clr-namespace:MyAssembly.AttachedProperties;assembly=MyAssembly">

    <TreeView attProps:DragDropAttProps.ScrollOnDragDrop="True">

这是一个使用列表框并进行自动滚动的简单而完整的拖放示例。我认为Andrew Stephens的回答一直在回答您的问题,因为它管理autoscroll,并且使用
附加属性
,这是一个好的做法

这是一个在示例窗口中从同一列表框拖放到同一列表框的完整示例

代码隐藏:

public partial class MainWindow : Window
{
    private const int dragMargin = 10;

    public MainWindow()
    {
        InitializeComponent();
    }


    private void ListBox_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.LeftButton != MouseButtonState.Pressed || list.SelectedItem == null)
            return;
        if (e.MouseDevice.DirectlyOver != null)
        {
            DragDrop.DoDragDrop(list, list.SelectedItem, DragDropEffects.All);
        }
    }

    private void list_Drop(object sender, DragEventArgs e)
    {
        var source = sender as ListBox;
        if (source == null)
            return;
        var item = e.Data.GetData(typeof (ContentControl));
        if (item == null)
            return;
        source.Items.Remove(item);
        var listAsTarget = sender as ListBox;
        if (listAsTarget == null)
            return;

        var mouseDirectitem = e.OriginalSource;
        var listItem = VisualFindParentFromType<ListBoxItem>(mouseDirectitem as UIElement);

        if (listItem == null)
        {
            listAsTarget.Items.Insert(0, item);
            return;
        }

        var insertBefore = true;
        var pointReletiveItem = e.GetPosition(listItem);
        Debug.WriteLine("Item Height: {0}", listItem.ActualHeight);
        Debug.WriteLine("Y: {0}", pointReletiveItem.Y);
        if (pointReletiveItem.Y > listItem.ActualHeight / 2)
            insertBefore = false;

        var index = listAsTarget.Items.IndexOf(listItem.Content);
        if (index >= 0)
        {
            listAsTarget.Items.Insert(insertBefore ? index : index + 1, item);
            return;
        }

        listAsTarget.Items.Add(item);
    }

    private T VisualFindParentFromType<T>(DependencyObject element) where T : UIElement
    {
        if (element == null)
            return default(T);
        if (element is T)
            return (T)element;
        return VisualFindParentFromType<T>(VisualTreeHelper.GetParent(element));
    }

    private T FindChildrenFromType<T>(DependencyObject element) where T : UIElement
    {
        if (element == null)
            return default(T);
        if (element is T)
            return (T) element;
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
        {
            var result = FindChildrenFromType<T>(VisualTreeHelper.GetChild(element, i));
            if (!Equals(default(T), result))
                return result;
        }
        return default(T);
    }

    private void list_DragOver(object sender, DragEventArgs e)
    {
        var source = e.Source as ListBox;

        if (source == null)
            return;
        var point = e.GetPosition(source);

        var scrollViewer = FindChildrenFromType<ScrollViewer>(source);
        if (scrollViewer == null)
            return;

        if (point.Y < dragMargin)
        {
            scrollViewer.LineUp();
        }
        else if (point.Y > Math.Abs(source.ActualHeight - dragMargin))
        {
            scrollViewer.LineDown();
        }
    }
}
公共部分类主窗口:窗口
{
私有常量int dragMargin=10;
公共主窗口()
{
初始化组件();
}
私有无效列表框\u MouseMove(对象发送方,MouseEventArgs e)
{
如果(例如:LeftButton!=鼠标按钮状态。按下| |列表。选择编辑项==null)
返回;
if(e.MouseDevice.DirectlyOver!=null)
{
DragDrop.DoDragDrop(list,list.SelectedItem,DragDropEffects.All);
}
}
私有作废列表(对象发送方、DragEventArgs e)
{
var source=发送方作为列表框;
if(source==null)
返回;
var item=e.Data.GetData(typeof(ContentControl));
如果(项==null)
返回;
source.Items.Remove(项目);
var listAsTarget=发送方作为列表框;
如果(listAsTarget==null)
返回;
var mouseDirectitem=e.OriginalSource;
var listItem=VisualFindParentFromType(作为UIElement的mouseDirectitem);
如果(listItem==null)
{
listAsTarget.Items.Insert(0,item);
返回;
}
var insertBefore=true;
var pointrelativeItem=e.GetPosition(listItem);
WriteLine(“项高度:{0}”,listItem.ActualHeight);
WriteLine(“Y:{0}”,pointrelativeItem.Y);
如果(PointRelativeItem.Y>listItem.ActualHeight/2)
insertBefore=false;
var index=listAsTarget.Items.IndexOf(listItem.Content);
如果(索引>=0)
{
listAsTarget.Items.Insert(insertBefore?索引:索引+1,项);
返回;
}
listAsTarget.Items.Add(item);
}
私有T VisualFindParentFromType(DependencyObject元素),其中T:UIElement
{
if(元素==null)
返回默认值(T);
if(元素为T)
<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <ListBox x:Name="list" Height="90" AllowDrop="True" MouseMove="ListBox_MouseMove" Drop="list_Drop" PreviewDragOver="list_DragOver">
        <ContentControl>
            Item 1
        </ContentControl>
        <ContentControl>
            Item 2
        </ContentControl>
        <ContentControl>
            Item 3
        </ContentControl>
        <ContentControl>
            Item 4
        </ContentControl>
        <ContentControl>
            Item 5
        </ContentControl>
        <ContentControl>
            Item 6
        </ContentControl>
        <ContentControl>
            Item 7
        </ContentControl>
        <ContentControl>
            Item 8
        </ContentControl>
        <ContentControl>
            Item 9
        </ContentControl>
    </ListBox>
</Grid>