【问题标题】:Get the correct treeview Item from WPF PreviewMouseRightButtonDown event of the TreeView Item从 TreeView 项的 WPF PreviewMouseRightButtonDown 事件中获取正确的树视图项
【发布时间】:2010-07-22 20:15:23
【问题描述】:

我的应用程序有一个动态级别的 WPF 树视图(TreeView 项使用具有可绑定富文本框的分层数据模板)我需要处理 TreeViewItem 的 PreviewMouseRightButtonDown 事件。

当我根据节点的级别右键单击树节点时,此事件会被多次命中(等于树视图项的级别。我认为这是因为此预览事件的隧道性质)

有人可以帮我确定正确的点击,它给出了我右键单击的确切树视图项目吗?

【问题讨论】:

    标签: wpf


    【解决方案1】:

    最简单的方法是使用冒泡事件MouseRightButtonDown 而不是隧道事件PreviewMouseRightButtonDown。您可以通过将 EventArgs 的 Handled 属性设置为 true 来将路由事件标记为已处理,这将阻止进一步的事件处理程序被调用。这样,只有最深的 TreeViewItem 会收到事件。

    如果不能使用 Preview 事件,另一种方法是使用 EventArgs 中的 OriginalSource 属性来查找实际单击的 UI 元素。这可能是您的 RichTextBox,因此您需要使用一种方法来查找 TreeViewItem 类型的可视祖先。在http://www.wpftutorial.net/LogicalAndVisualTree.html 有一个获取给定类型的祖先的方法示例:

    public static class VisualTreeHelperExtensions
    {
        public static T FindAncestor<T>(DependencyObject dependencyObject)
            where T : class
        {
            DependencyObject target = dependencyObject;
            do
            {
                target = VisualTreeHelper.GetParent(target);
            }
            while (target != null && !(target is T));
            return target as T;
        }
    }
    

    因此,您可以调用 ((DependencyObject)e.OriginalSource).FindAncestor&lt;TreeViewItem&gt;() 来查找被点击的 TreeViewItem。如果您这样做,您应该将事件处理程序附加到 TreeView 本身而不是 TreeViewItems。这将捕获任何 TreeViewItem 中的单击,因为它们都在树中,但它只会被调用一次。


    编辑:正如您所注意到的,如果目标是 FrameworkContentElement,则该方法不起作用,因为它不是 Visual。你可以这样做:

    public static class VisualTreeHelperExtensions
    {
        public static T FindAncestor<T>(object dependencyObject)
            where T : DependencyObject
        {
            var target = (DependencyObject)dependencyObject;
            do
            {
                var visualParent = target is Visual ? VisualTreeHelper.GetParent(target) : null;
                if (visualParent != null)
                {
                    target = visualParent;
                }
                else
                {
                    var logicalParent = LogicalTreeHelper.GetParent(target);
                    if (logicalParent != null)
                    {
                        target = logicalParent;
                    }
                    else
                    {
                        return null;
                    }
                }
            }
            while (!(target is T));
            return (T)target;
        }
    }
    

    然后您应该能够通过执行VisualTreeHelperExtensions.FindAncestor&lt;TreeViewItem&gt;(e.OriginalSource) 从 OriginalSource 获取 TreeViewItem。

    【讨论】:

    • 感谢您的想法,但在我的情况下,我必须使用预览事件,因为树视图项具有模板的丰富文本框,并且它不会触发 TreeViewItem 的冒泡事件。 e.OriginalSource 不是richtextbox,它是流文档或运行或richtextbox 内的其他元素(将根据我右键单击的位置而变化)
    • @Niruka:抱歉,我包含的方法没有处理像 Run 这样的 FrameworkContentElement 对象。请参阅我的更新答案。
    • 非常感谢。第二种方法奏效了。我对它做了一个非常小的修改。行目标 = ((FrameworkElement)target).Parent;已更改为 target = VisualTreeHelper.GetParent(target);似乎,在检索 TreeViewItem 的过程中,当我们点击 Border 元素但 VisualTreeHelper.GetParent(target); 时,属性 ((FrameworkElement)target).Parent 返回了 null;将返回正确的父级。这应该有一个合乎逻辑的解释,但我对 WPF 太陌生了。再次感谢。顺便说一句,我不确定如何将此问题的状态设置为已回答抱歉。
    猜你喜欢
    • 2013-08-14
    • 1970-01-01
    • 2015-10-25
    • 1970-01-01
    • 2011-12-19
    • 1970-01-01
    • 1970-01-01
    • 2012-08-16
    • 2010-11-26
    相关资源
    最近更新 更多