2010-07-21 149 views
0

我有我的应用程序需要处理TreeViewItem的PreviewMouseRightButtonDown事件的动态级别(TreeView项目使用Hierachical数据模板具有可绑定的richtextbox)的WPF treeview。从TreeView的WPF PreviewMouseRightButtonDown事件获取正确的TreeView项目

当我用鼠标右键单击基于节点的水平树节点此事件被击中多次(等于TreeView项的水平。我认为这是因为这个预览事件的隧道性质)

人请帮助我确定正确的命中,给出我右键单击的确切树视图项目?

回答

1

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

如果您不能使用预览事件,另一种方法是使用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<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<TreeViewItem>(e.OriginalSource)从OriginalSource得到树型视图。

+0

感谢您的想法,但在我的情况下,我不得不使用预览事件,因为树视图项目具有模板的richtextbox,并且它不会触发TreeViewItem的冒泡事件。 e.OriginalSource不是richtextbox它是richtextbox中的flowdocument或Run或其他元素(将根据我右键单击的位置进行更改) – Niruka 2010-07-21 14:00:52

+0

@Niruka:对不起,我包含的方法没有处理FrameworkContentElement象Run的对象。看到我更新的答案。 – Quartermeister 2010-07-21 15:40:06

+0

非常感谢。第二种方法奏效。我做了一个非常小的修改。该行目标=((FrameworkElement)目标).Parent;已更改为 target = VisualTreeHelper.GetParent(target); 看起来像,在回顾TreeViewItem的方式,属性((FrameworkElement)目标).Parent已经返回null,当我们击中一个Border元素,但VisualTreeHelper.GetParent(目标);将返回正确的父母。这应该有一个合理的解释,但我对WPF太新了。再次感谢。顺便说一句,我不知道如何设置这个问题的状态作为回答抱歉。 – Niruka 2010-07-22 09:10:49