WPF TreeView上的拖放和滚动条

10

我们的应用程序使用MVVM模式,在窗口中有两个TreeView,允许将第一个树中的项目拖放到第二个树中。为避免代码后台,我们使用行为将拖放与ViewModel绑定。

该行为实现得非常像这个示例,并且可以很好地工作,但存在一个错误。

情况是树比显示它的窗口大,因此它具有垂直滚动条。当选择了项目并且用户想要滚动时,程序会开始拖放(这会阻止实际滚动,因此不是我们想要的结果)。

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

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

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

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


编辑

结合Nikolay的链接,我使用了一个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;
    }

非常感谢,这真是救了我的一天。找到IsMouseOverScrollbar太棒了。 - Sachin
2个回答

4
请看Josh Smith的这篇文章,它实现了ListView的拖放行为。该实现代码可以处理滚动条和其他DnD问题(例如拖动阈值、精确鼠标坐标等)。这种行为也可以轻松地适用于TreeView。

虽然这个实现对我来说并不可用,但是IsMouseOverScrollbar属性向我展示了如何遍历VisualTree并获取一个值,指示鼠标是否悬停在滚动条上的一些概念,这确实解决了我的问题。谢谢! - Matten

1

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接