[英]WPF HitTest to get ListBoxItem
首先,第一件事:在Visual Studio 2010中,我有一个使用C#和MVVM(MVVM Light)的WPF项目。
我有一个Canvas控件,其中有一个ListBox-每个ListBoxItem都可以通过鼠标拖动来移动(每个都有一个DataTemplate包含一个Thumb控件,以允许拖动每个项目)。
如下所示:
<DataTemplate>
<Grid Background="Transparent">
<Thumb Name="myThumb" Template="{StaticResource NodeVisualTemplateRegular}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="DragDelta">
<cmd:EventToCommand Command="{Binding ChatNodeListViewModel.DragDeltaCommand, Source={StaticResource Locator}}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Thumb>
</Grid> </DataTemplate>
如您所见,这里有一个处理拖动部分的命令(DeltaDragCommand)。
所有这些都不是问题,但是随后我想添加通过单击和拖动动作在Canvas控件上平移的功能。 这就是与上述ListBoxItems拖动产生冲突的地方。
Canvas pan的内容在后面的代码中处理,事件的订阅如下所示:
NodeDragScrollViewer.PreviewMouseLeftButtonDown += OnMouseLeftButtonDown;
NodeDragScrollViewer.PreviewMouseLeftButtonUp += OnMouseLeftButtonUp;
NodeDragScrollViewer.MouseMove += OnMouseMove;
NodeDragScrollViewer.PreviewMouseWheel += OnPreviewMouseWheel;
NodeDragScrollViewer.ScrollChanged += OnScrollViewerScrollChanged;
我们在此处看到的事件在ScrollViewer(Canvas控件所在的控件)上运行。 问题在于这些事件位于ListBoxItems的“顶部”-在单击ListBoxItem的拖动之前,将激活画布平移的单击。
现在,我看到的一个解决方案是使用VisualTreeHelper HitTest方法找出被单击的内容。 如果可以确定是否单击了ListBoxItem,则可以忽略Canvas平移操作,并使事情像以前一样进行。
我面临的问题是我无法正常工作。 我似乎有人解释了它应该如何工作,并借用了此操作的代码。 我在这里显示该代码:
Point pt = new Point();
VisualTreeHelper.HitTest(NodeDragCanvas, null,
new HitTestResultCallback(MyHitTestResult),
new PointHitTestParameters(pt));
private HitTestResultBehavior MyHitTestResult(HitTestResult result)
{
var p = FindParent<ListBoxItem>(result.VisualHit);
//Set the behavior to return visuals at all z-order levels.
return HitTestResultBehavior.Continue;
}
public static T FindParent<T>(DependencyObject child) where T : DependencyObject
{
//get parent item
DependencyObject parentObject = VisualTreeHelper.GetParent(child);
//we've reached the end of the tree
if (parentObject == null) return null;
//check if the parent matches the type we're looking for
T parent = parentObject as T;
if (parent != null)
return parent;
else
return FindParent<T>(parentObject);
}
如果您查看HitTestResultBehaviour的内容,则在这里检查单击的控件。 我希望它将是一个ListBoxItem ...但始终返回'null'。 我知道该方法可以触发多次,但是我从未见过var p(在这种情况下)不是空值。 但是,如果尝试使用FindParent < ListBox >,则会返回ListBox。 它中的项目数量正确,似乎与我期望的一样。 但这对我不起作用,因为我的ListBox只是Canvas的大小。
看来这是关键点,但是我不知道还有什么尝试的方法,所有的研究途径似乎都回到了这种方法。
谁能提供任何指导? 谢谢
是的,显然您需要在Canvas上使用PreviewXXX事件,否则您将无法获得Canvas中ListBoxItems的鼠标事件,因为ListBoxItem已经吃掉了它们。
您可能需要考虑重组代码,以便使用MyListBox(或任何您想调用的东西)而不使用ListBox,并在其中捕获ListBoxItem鼠标事件,并仅处理Canvas在Canvas中的拖动。 您现在拥有的方式是将两种情况完全分开时将它们混合在一起。 画布应处理其内容,列表框应处理其内容。
如果您想保留现在的代码,请查看MouseEventArgs,原始源,发送者等。其中一个可能具有原始发送者,但可能是TextBlock而不是ListBoxItem,因为顶级商品,所以...
Google围绕着一个著名的类VisualTreeExtensions
并使用它。 当您获取TextBlock或其他内容时,您可以执行((DependencyObject)e.OriginalSource).GetVisualAncestor<ListBoxItem>()
,如果它不为null,则表示您位于ListBox内部。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.