在滚动条上的WPF TreeView中拖放

时间:2021-01-12 00:08:31

we're using the MVVM pattern in our application and in a window, we have two TreeViews allowing to drag items from the first and drop it on the second tree. To avoid code behind, we're using behaviours to bind the drag and drop against the ViewModel.

我们在应用程序中使用MVVM模式,在一个窗口中,我们有两个TreeViews,可以从第一个树拖拽项目并将其放到第二个树中。为了避免代码落后,我们使用行为将拖放绑定到ViewModel上。

The behaviour is implemented pretty much like this example and working like a charm, with one bug.

该行为的实现与本例非常相似,使用一个bug就像魔法一样工作。

The scenario is a tree which is bigger than the window displaying it, therefore it has a vertical scroll bar. When an item is selected and the user wants to scroll, the program starts drag and drop (which prevents the actual scrolling and therefore isn't what we want).

这个场景是一个比显示它的窗口大的树,因此它有一个垂直的滚动条。当一个项目被选中并且用户想要滚动时,程序开始拖放(这阻止了实际的滚动,因此这不是我们想要的)。

This isn't very surprising as the scrollbar is contained in the TreeView control. But I'm unable to determine safely if the mouse is over the scrollbar or not.

这并不奇怪,因为滚动条包含在TreeView控件中。但是我无法确定鼠标是否在滚动条上。

The TreeViewItems are represented by a theme using Borders, Panels and so on, so a simple InputHitTest isn't as simple as one may think.

TreeViewItems用边框、面板等主题来表示,因此一个简单的InputHitTest并不像人们想象的那么简单。

Has anybody already encountered the same problem?

有没有人遇到过同样的问题?

If more code coverage of the problem is required, I can paste some lines from the .xaml.

如果需要对问题进行更多的代码覆盖,我可以从.xaml粘贴一些行。


Edit

编辑

Incorporating Nikolays link I solved the problem using a IsMouseOverScrollbar method, if anyone has this problem in the future the code from above must be altered in the following way:

结合Nikolays链接,我使用IsMouseOverScrollbar方法解决了这个问题,如果将来有人遇到这个问题,上面的代码必须按照以下方式修改:

private static void PreviewMouseMove(object sender, MouseEventArgs e)
{
    if (e.LeftButton != MouseButtonState.Pressed || startPoint == null)
        return;

    if (!HasMouseMovedFarEnough(e))
        return;

   if (IsMouseOverScrollbar(sender, e.GetPosition(sender as IInputElement)))
   {
       startPoint = null;
       return;
   }

   var dependencyObject = (FrameworkElement)sender;
   var dataContext = dependencyObject.GetValue(FrameworkElement.DataContextProperty);
   var dragSource = GetDragSource(dependencyObject);

   if (dragSource.GetDragEffects(dataContext) == DragDropEffects.None)
        return;

   DragDrop.DoDragDrop(
            dependencyObject, dragSource.GetData(dataContext), dragSource.GetDragEffects(dataContext));
}


    private static bool IsMouseOverScrollbar(object sender, Point mousePosition)
    {
        if (sender is Visual)
        {
            HitTestResult hit = VisualTreeHelper.HitTest(sender as Visual, mousePosition);

            if (hit == null) return false;

            DependencyObject dObj = hit.VisualHit;
            while(dObj != null)
            {
                if (dObj is ScrollBar) return true;

                if ((dObj is Visual) || (dObj is Visual3D)) dObj = VisualTreeHelper.GetParent(dObj);
                else dObj = LogicalTreeHelper.GetParent(dObj);
            }
        }

        return false;
    }

2 个解决方案

#1


4  

Take a look at this implementation of Drag and Drop behaviour for ListView by Josh Smith. It has code to deal with scrollbars and some other unobvious problems of DnD (like drag treshold, precise mouse coordinates and such). This behaviour can be easily adopted to work with TreeViews too.

看看Josh Smith在ListView中拖放行为的实现。它有用于处理滚动条和DnD的其他一些不明显的问题的代码(比如拖放treshold、精确的鼠标坐标等等)。这种行为也可以很容易地用于树视图。

#2


0  

I had the same Problem. I solved it by placing the TreeView inside a ScrollViewer.

我也有同样的问题。我把TreeView放在一个ScrollViewer中解决了这个问题。

<ScrollViewer Grid.Column="0">
  <TreeView BorderThickness="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MouseMove="DeviceTree_OnMouseMove" PreviewMouseLeftButtonDown="DeviceTree_OnPreviewMouseLeftButtonDown" Name="DeviceTree" ItemsSource="{Binding Devices}"/>
</ScrollViewer>

#1


4  

Take a look at this implementation of Drag and Drop behaviour for ListView by Josh Smith. It has code to deal with scrollbars and some other unobvious problems of DnD (like drag treshold, precise mouse coordinates and such). This behaviour can be easily adopted to work with TreeViews too.

看看Josh Smith在ListView中拖放行为的实现。它有用于处理滚动条和DnD的其他一些不明显的问题的代码(比如拖放treshold、精确的鼠标坐标等等)。这种行为也可以很容易地用于树视图。

#2


0  

I had the same Problem. I solved it by placing the TreeView inside a ScrollViewer.

我也有同样的问题。我把TreeView放在一个ScrollViewer中解决了这个问题。

<ScrollViewer Grid.Column="0">
  <TreeView BorderThickness="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MouseMove="DeviceTree_OnMouseMove" PreviewMouseLeftButtonDown="DeviceTree_OnPreviewMouseLeftButtonDown" Name="DeviceTree" ItemsSource="{Binding Devices}"/>
</ScrollViewer>