wpf treeviewitem鼠标双击

时间:2014-09-11 20:14:40

标签: wpf

我在识别所选TreeViewItem的名称时遇到问题;我在树视图中有以下结构:

 + Module 1 (name k1)
   - Sub Module 1 (name s1)
 + Module 2 (name k2)
   - Sub Module 2 (name s2)
 + Module 3 Name (k3)
   - Sub Module 3 (name s3)
   - Sub Module 4 (name s4)

我是xaml:

<TreeView x:Name="treview_Menu">
   <TreeView.ItemContainerStyle>
      <Style TargetType="{x:Type TreeViewItem}">
         <EventSetter Event="MouseDoubleClick" Handler="OnItemMouseDoubleClick" />
      </Style>
   </TreeView.ItemContainerStyle>
</TreeView>

在代码中我有这个:

Private Sub OnItemMouseDoubleClick(sender As Object, args As MouseButtonEventArgs)
   MsgBox(sender.name)
End Sub

在上面的代码中总是返回顶级节点的名称,例如,如果我双击sub_module 3 o sub_module 4总是返回Module_3的名称,同样的情况发生在sub_module 1和sub_module 2 ...因为我可以解决这个问题?

1 个答案:

答案 0 :(得分:5)

我认为问题是ItemContainerStyle仅适用于第一级节点(我相信这是TreeView继承自ItemsControlItemContainerStyle的方式所致继承自那里 - 只适用于Items的基本ItemsControl。无论如何,我要去一个......)

您可以修改它,而不是将样式分配给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事件(Microsoft使用该事件显然触发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());
    }
}

然而,因为预览事件隧道向下,它不幸在包含的项目上触发一次,而不是包含的项目,所以我们回到了正方形1.我们可以在这里查看args.OriginalSource但是我们我基本上已经到了建议采用不同解决方案的阶段:

单独替代

另一种选择是在其双击事件中向整个TreeView添加一个事件监听器,然后只需查找其TreeViewItem所在的OriginalSource。 (如果你想处理它并阻止它传播/引起其他影响,你需要改为上面的PreviewMouseLeftButtonDown事件,而不是如上所述。)

为此,您可以选择MouseButtonEventArgs args并考虑args.OriginalSource(这是您点击的可视树上最顶层的元素),然后您会遇到一些情况:要么是根本不在任何TreeViewItem内,或者它本身就是您需要的TreeViewItem,或者第三种可能性是OriginalSource是您需要的TreeViewItem内的某个元素(这是最多的)可能的情况 - 从测试开始,您通常会点击TextBlock中包含的TreeViewItem,在这种情况下,您可以递归查找父项,直到您点击TreeViewItem类型的第一个父项。 (您可以使用VisualTreeHelper GetParent方法执行此操作。)

基本上,上述算法可以概括为只是递归检查当前项目以查看它是TreeViewItem类型还是TreeView否则你将当前项目作为其父项并递归...如果你以TreeViewItem结束,你有所需的项目,否则如果你点击一个项目,你将最终到TreeView

PS:因为我不能写VB,我认为解释上述算法可能比尝试编写它更好 - 但我希望上面的解释仍然对你有用:)