[英]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.