【问题标题】:In WPF, how do I select the treeview item under my cursor on right-click?在 WPF 中,如何在右键单击时选择光标下的树视图项?
【发布时间】:2009-04-28 13:35:59
【问题描述】:

在 WPF 中,当我右键单击树视图项时,我希望在显示上下文菜单之前选择/激活它。

这听起来很简单,但是包含 hierachicalDataTemplate 会使事情变得有些复杂。

我有以下树视图:

<TreeView 
            x:Name="trv"
            ContextMenu="{StaticResource contextMenu}"
            ItemTemplate="{StaticResource treeHierarchicalDataTemplate}"
            ItemsSource="{Binding Source={StaticResource meetingItems}}" >

            <TreeView.ItemContainerStyle>
                <Style TargetType="{x:Type TreeViewItem}">
                    <EventSetter Event="TreeViewItem.PreviewMouseRightButtonDown" Handler="trv_PreviewMouseRightButtonDown"/>
                    <Setter Property="IsExpanded" Value="True"></Setter>
                </Style>
            </TreeView.ItemContainerStyle>
        </TreeView>

这是我的事件处理程序...

private void trv_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
    TreeViewItem item = sender as TreeViewItem;
    if (item != null)
    {
        item.Focus();
        e.Handled = true;
    }

}

请注意我如何在上面添加 EventSetter。这几乎有效。但它只选择根级树视图节点(即我右键单击的节点的根父节点)。这可能是因为我的分层数据模板?此模板可以包含相同类型的子级。

这是我的分层数据模板...

<HierarchicalDataTemplate x:Key="treeHierarchicalDataTemplate" 
                          ItemsSource="{Binding Path=ChildMeetingItems}">
    <HierarchicalDataTemplate.Triggers>
        <DataTrigger Binding="{Binding Path=Red}" Value="True">
            <Setter TargetName="img" Property="Image.Source" Value="pack://siteoforigin:,,,/images/bookRed.png"></Setter>
        </DataTrigger>
    </HierarchicalDataTemplate.Triggers>
    <StackPanel 
        x:Name="treeViewItemPanel"
        Background="Transparent"
        Orientation="Horizontal">
        <Image Width="16" Height="16"  x:Name="img" Margin="0,0,4,0" Source="pack://siteoforigin:,,,/images/bookGreen.png"></Image>
        <TextBlock Foreground="DarkGray" Text="{Binding DisplayIndex}" Margin="0,0,5,0"></TextBlock>
        <TextBlock Text="{Binding Summary}"></TextBlock>
    </StackPanel>
</HierarchicalDataTemplate>

知道为什么我右键单击时只选择根节点而不是子节点吗?

【问题讨论】:

    标签: wpf treeview treeviewitem


    【解决方案1】:

    这是因为 ItemContainerStyle 不被子节点继承。 您需要在您的 HierarchicalDataTemplate 的 ItemContainerStyle 上添加相同的 EventSetter。

    <HierarchicalDataTemplate x:Key="treeHierarchicalDataTemplate" 
                              ItemsSource="{Binding Path=ChildMeetingItems}">
        <HierarchicalDataTemplate.Triggers>
            <DataTrigger Binding="{Binding Path=Red}" Value="True">
                <Setter TargetName="img" Property="Image.Source" Value="pack://siteoforigin:,,,/images/bookRed.png"></Setter>
            </DataTrigger>
        </HierarchicalDataTemplate.Triggers>
        <StackPanel 
            x:Name="treeViewItemPanel"
            Background="Transparent"
            Orientation="Horizontal">
            <Image Width="16" Height="16"  x:Name="img" Margin="0,0,4,0" Source="pack://siteoforigin:,,,/images/bookGreen.png"></Image>
            <TextBlock Foreground="DarkGray" Text="{Binding DisplayIndex}" Margin="0,0,5,0"></TextBlock>
            <TextBlock Text="{Binding Summary}"></TextBlock>
        </StackPanel>
    
    <HierarchicalDataTemplate.ItemContainerStyle>
                    <Style TargetType="{x:Type TreeViewItem}">
                        <EventSetter Event="TreeViewItem.PreviewMouseRightButtonDown" Handler="trv_PreviewMouseRightButtonDown"/>                    
                    </Style>
                </HierarchicalDataTemplate.ItemContainerStyle>
    </HierarchicalDataTemplate>
    

    【讨论】:

    • 谢谢丹尼斯。这就说得通了。我仍然得到奇怪的行为......如果我在分层数据模板和树视图上都设置了 ItemContainerStyle,那么它仍然和以前一样。如果我只在hierarchicalDataTemplate 上设置ItemContainerStyle,它会做同样的事情,但这次只针对第二级的节点。奇怪的。有什么想法吗?
    • 啊,有趣。这是由于 e.Handled = true 而发生的。虽然不是 100% 确定为什么......
    • 因为您正在处理隧道事件(PreviewXXX 事件)。这些事件从树的顶部到底部,因此如果您在根处设置 e.Handled=true,它将停在那里并且不会沿着树向下隧道到您的项目。
    • 我发现使用 MouseRightButtonDown(而不是预览版)更自然。这意味着您应该使用e.Handled = true,但更容易集成Ctrl-右键单击逻辑来处理多项选择。 (由于带有预览事件的隧道而不是e.Handled,因此Ctrl-右键单击选择了层次结构中的所有节点。)
    【解决方案2】:

    只需从您的事件处理程序中评论e.Handler=true

    像这样:

    private void trv_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
    {
        TreeViewItem item = sender as TreeViewItem;
        if (item != null)
        {
            item.Focus();
           // e.Handled = true;
        }
    
    }
    

    【讨论】:

    • 这适用于我的多级树视图。 e.Handled = true; 将停止处理程序事件并在第一级停止它,这就是为什么只能选择根元素或第一级元素的原因。
    【解决方案3】:

    我遇到了同样的问题 - 无法获得正确的选定树项。而不是使用PreviewMouseRightButtonDown 事件,我使用了StackPanel 的相同事件,它还存储所有需要的数据:

    <StackPanel DataContext="{Binding}" MouseLeftButtonDown="StackPanel_MouseLeftButtonDown">
    ....
    </StackPanel>
    

    以及事件处理程序代码隐藏:

     private void StackPanel_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                StackPanel panel = sender as StackPanel;
                if(panel==null)return;
                MyTreeViewItem myClicked = panel.DataContext as MyTreeViewItem;
                if (myClicked == null) return;
    ...
    }
    

    MyTreeViewItem 是我自定义的数据类型; myClicked 现在存储与单击的树项关联的数据。 希望它能帮助像我这样的人。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多