簡體   English   中英

WPF HitTest獲取ListBoxItem

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM