繁体   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