我认为的问题是ItemContainerStyle 仅适用于第一级节点(我认为这是由于TreeView 继承自ItemsControl 和ItemContainerStyle 从那里继承的方式 - 仅适用于到ItemsControl 的基本Items。无论如何,我要去一个......)
您可以修复它,而不是将样式分配给ItemContainerStyle,只需将其移动到Resources,如下所示:
<TreeView.Resources>
<Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource {x:Type TreeViewItem}}">
<EventSetter Event="MouseDoubleClick" Handler="OnItemMouseDoubleClick"/>
</Style>
</TreeView.Resources>
根据您的需要,这可能无法按您的意愿工作...
因为这会为每个 TreeViewItem 添加一个触发器 - 不幸的是,它们嵌套如下:
<TreeViewItem Header="Module 1">
<TreeViewItem Header="Sub Module 1"/>
</TreeViewItem>
<TreeViewItem Header="Module 2">
<TreeViewItem Header="Sub Module 1"/>
<TreeViewItem Header="Sub Module 2"/>
</TreeViewItem>
因此,根据您实际使用代码的目的,事件在 外部和内部模块上触发可能是个问题。
在ClickEvent 中处理此问题的常用方法是在代码中将args.Handled 设置为True,这会阻止事件“冒泡”到更高级别。但不幸的是,这不适用于MouseDoubleClick 事件,因为它们被触发的方式。 (好一个微软... xD)
一个可能的答案在这里:https://stackoverflow.com/a/6326181/3940783
基本上,我们放弃了MouseDoubleClick 事件,而是使用PreviewMouseLeftButtonDown 事件(微软显然使用它来触发MouseDoubleClick 事件)。无论如何,我们可以像这样让它触发一次:
(请原谅C#,我试图从wpf角度回答这个问题,但我不知道等效的VB代码)
OnItemPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
if (e.ClickCount == 2) {
e.Handled = true;
var treeViewItem = sender as TreeViewItem;
MessageBox.Show(treeViewItem.Header.ToString());
}
}
但是,由于 Preview 事件向下隧道,不幸的是它会在包含项目上触发一次,而不是在包含项目上,所以我们回到第 1 格。我们可以在这里查看args.OriginalSource,但我们是基本上已经到了建议采用不同解决方案的阶段:
单独选择
另一种选择是在其双击事件上为整个TreeView 添加一个事件侦听器,然后简单地查找TreeViewItem 其OriginalSource 所在的位置。 (如果您想处理它并阻止它传播/引起其他影响,您需要改为挂钩到上面的 PreviewMouseLeftButtonDown 事件)。
为此,您可以使用MouseButtonEventArgs args 并考虑args.OriginalSource(这是您单击的可视化树上最顶部的元素),然后您会遇到一些情况:要么它不在任何@ 内987654349@,或者它本身就是您需要的TreeViewItem,或者第三种可能性是 OriginalSource 是您需要的TreeViewItem 内部某处的元素(这是最可能的情况 - 从测试中,您通常单击TextBlock 包含在 TreeViewItem) 中,在这种情况下,您可以递归地查找父级,直到找到类型为 TreeViewItem 的第一个父级。 (您可以使用VisualTreeHelper GetParent 方法来做到这一点。)
基本上,上述算法可以总结为递归检查当前项目以查看它是否属于TreeViewItem 或TreeView 类型,否则您将当前项目设为其父项并递归...如果您以@ 结束987654359@,你有需要的项目,否则如果你在项目外点击,你最终会在TreeView。
PS:由于我不会写VB,我认为解释上述算法可能比尝试编写它更好 - 但我希望上述解释仍然对你有用:)