滚动时禁用拖放

本文关键字:拖放 滚动 | 更新日期: 2023-09-27 17:56:25

我已经在WPF中实现了TreeView的拖放功能。

一切正常,但是当滚动显示在树视图中时,如果我在树中选择一个项目,然后尝试滚动(垂直或水平),TreeView 会尝试执行拖放操作。

以下是源代码:

class TreeViewRearranger
{
    private TreeView mTreeView;
    private int MOVE_TOLERANCE = 10;
    private TreeViewItem mDraggedItem = null;
    private TreeViewItem mTargetDrop = null;
    private DropAdorner mDropAdorner = null;
    public void Initialize(TreeView treeView)
    {
        mTreeView = treeView;
        SetupDragDropEvents();
    }
    private void SetupDragDropEvents()
    {
        mTreeView.MouseDown += mTreeView_MouseDown;
        mTreeView.MouseMove += mTreeView_MouseMove;
        mTreeView.DragOver += mTreeView_DragOver;
        mTreeView.Drop += mTreeView_Drop;
        mTreeView.DragEnter += mTreeView_DragEnter;
        mTreeView.DragLeave += mTreeView_DragLeave;
    }
    void mTreeView_MouseDown(object sender, MouseButtonEventArgs e)
    {
        if (e.ChangedButton != MouseButton.Left)
            return;
        mLastMouseDown = e.GetPosition(mTreeView);
    }
    void mTreeView_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.LeftButton != MouseButtonState.Pressed)
            return;
        Point currentPosition = e.GetPosition(mTreeView);
        if ((Math.Abs(currentPosition.X - mLastMouseDown.X) <= MOVE_TOLERANCE) &&
            (Math.Abs(currentPosition.Y - mLastMouseDown.Y) <= MOVE_TOLERANCE))
            return;
        StartDrag();
    }
    void mTreeView_DragLeave(object sender, DragEventArgs e)
    {
        RemoveAdorners();
    }
    void mTreeView_DragEnter(object sender, DragEventArgs e)
    {
        AdornerLayer layer = AdornerLayer.GetAdornerLayer(mTreeView);
        mDropAdorner = new DropAdorner(mTreeView);
        layer.Add(mDropAdorner);
    }
    private Point mLastMouseDown;
    private void StartDrag()
    {
        mDraggedItem = mTreeView.SelectedItem as TreeViewItem;
        if (mDraggedItem == null) return;
        DragDropEffects finalDropEffect =
            DragDrop.DoDragDrop(
                mTreeView, mTreeView.SelectedValue, DragDropEffects.Move);
        // Check that target is not null and item is 
        // dragging(moving)
        if ((finalDropEffect != DragDropEffects.Move) || (mTargetDrop == null))
            return;
        // A Move drop was accepted
        if (mDraggedItem.Header.ToString().Equals(mTargetDrop.Header.ToString()))
            return;
        PerformDragDrop(mDraggedItem, mTargetDrop);
        mTargetDrop = null;
        mDraggedItem = null;
    }
    private void PerformDragDrop(TreeViewItem source, TreeViewItem destination)
    {
        if (source == null || destination == null)
            return;
        OnRearrange(source, destination);
    }
    private static TreeViewItem GetParentTreeViewItem(DependencyObject item)
    {
        if (item == null)
            return null;
        DependencyObject parent = VisualTreeHelper.GetParent(item);
        TreeViewItem parentTreeViewItem = parent as TreeViewItem;
        return parentTreeViewItem ?? GetParentTreeViewItem(parent);
    }
    private void OnRearrange(TreeViewItem source, TreeViewItem destination)
    {
        if (source == null || destination == null)
            return;
        TreeNode sourceNode = source.Tag as TreeNode;
        TreeNode destinationNode = destination.Tag as TreeNode;
        TreeNode targetNode = destinationNode;
        if (!destination.IsExpanded || destination.Items.Count == 0)
        {
            TreeViewItem parentItem = GetParentTreeViewItem(destination);
            if (parentItem == null)
            {
                targetNode = mTreeView.Tag as TreeNode;
            }
            else
            {
                targetNode = parentItem.Tag as TreeNode;
            }
        }
        int index = targetNode.Children.IndexOf(destinationNode) + 1;
        // performed a rearrange from sourceNode to targetNode at index
    }
    void mTreeView_DragOver(object sender, DragEventArgs e)
    {
        Point currentPosition = e.GetPosition(mTreeView);
        if ((Math.Abs(currentPosition.X - mLastMouseDown.X) <= MOVE_TOLERANCE) &&
            (Math.Abs(currentPosition.Y - mLastMouseDown.Y) <= MOVE_TOLERANCE))
            return;
        // Verify that this is a valid drop and then store the drop target
        TreeViewItem item = GetNearestContainer(e.OriginalSource as UIElement);
        if (CheckDropTarget(mDraggedItem, item))
        {
            e.Effects = DragDropEffects.Move;
            UpdateDropAdorner(item);
        }
        else
        {
            e.Effects = DragDropEffects.None;
            UpdateDropAdorner(null);
        }
        e.Handled = true;
    }
    void mTreeView_Drop(object sender, DragEventArgs e)
    {
        e.Effects = DragDropEffects.None;
        e.Handled = true;
        // Verify that this is a valid drop and then store the drop target
        TreeViewItem targetItem = GetNearestContainer
            (e.OriginalSource as UIElement);
        if (targetItem == null || mDraggedItem == null)
            return;
        mTargetDrop = targetItem;
        e.Effects = DragDropEffects.Move;
        UpdateDropAdorner(mTargetDrop);
        RemoveAdorners();
    }
    private void UpdateDropAdorner(TreeViewItem targetItem)
    {
        mDropAdorner.UpdateTargetPosition(targetItem);
    }
    private TreeViewItem GetNearestContainer(UIElement element)
    {
        // Walk up the element tree to the nearest tree view item.
        TreeViewItem container = element as TreeViewItem;
        while ((container == null) && (element != null))
        {
            element = VisualTreeHelper.GetParent(element) as UIElement;
            container = element as TreeViewItem;
        }
        return container;
    }
    private bool CheckDropTarget(TreeViewItem sourceItem, TreeViewItem targetItem)
    {
        if (sourceItem == null || targetItem == null)
            return false;
        if (sourceItem.Header.ToString().Equals(targetItem.Header.ToString()))
            return false;
        if (targetItem.IsDescendantOf(sourceItem))
            return false;
        return true;
    }
    private void RemoveAdorners()
    {
        AdornerLayer layer = AdornerLayer.GetAdornerLayer(mTreeView);
        layer.Remove(mDropAdorner);
        mDropAdorner = null;
    }
}

滚动时禁用拖放

您可能需要将

自己附加到滚动查看器 ScrollChanged 事件,当触发该事件时,您可以禁用拖放。我还没有尝试过,但我认为这可能是一个尝试的起点

ScrollViewer scrollViewer = GetVisualChild<ScrollViewer>(mTreeView);
        scrollViewer.ScrollChanged += new ScrollChangedEventHandler(scrollViewer