【发布时间】:2010-07-22 20:15:23
【问题描述】:
我的应用程序有一个动态级别的 WPF 树视图(TreeView 项使用具有可绑定富文本框的分层数据模板)我需要处理 TreeViewItem 的 PreviewMouseRightButtonDown 事件。
当我根据节点的级别右键单击树节点时,此事件会被多次命中(等于树视图项的级别。我认为这是因为此预览事件的隧道性质)
有人可以帮我确定正确的点击,它给出了我右键单击的确切树视图项目吗?
【问题讨论】:
标签: wpf
我的应用程序有一个动态级别的 WPF 树视图(TreeView 项使用具有可绑定富文本框的分层数据模板)我需要处理 TreeViewItem 的 PreviewMouseRightButtonDown 事件。
当我根据节点的级别右键单击树节点时,此事件会被多次命中(等于树视图项的级别。我认为这是因为此预览事件的隧道性质)
有人可以帮我确定正确的点击,它给出了我右键单击的确切树视图项目吗?
【问题讨论】:
标签: wpf
最简单的方法是使用冒泡事件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<TreeViewItem>() 来查找被点击的 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 获取 TreeViewItem。
【讨论】: