拖放滚动条上的WPF TreeView

时间:2012-04-16 08:49:29

标签: c# wpf drag-and-drop treeview behavior

我们在应用程序和窗口中使用MVVM模式,我们有两个TreeView允许从第一个树中拖动项目并将其放在第二个树上。为了避免代码落后,我们使用行为来绑定对ViewModel的拖放。

该行为几乎实现like this example并且像魅力一样,只有一个错误。

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

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

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

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

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


修改

合并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 个答案:

答案 0 :(得分:4)

看看this implementation of Drag and Drop behaviour for ListView by Josh Smith。它有处理滚动条的代码和DnD的一些其他不明显的问题(如拖动阈值,精确的鼠标坐标等)。这种行为也可以很容易地用于TreeViews。

答案 1 :(得分:0)

我遇到了同样的问题。我通过将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>