我们的应用程序使用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