C# 如何在wpf中的层次数据模板中显示treeview项的上下文菜单

C# 如何在wpf中的层次数据模板中显示treeview项的上下文菜单,c#,wpf,treeview,contextmenu,C#,Wpf,Treeview,Contextmenu,如何使用分层数据模板在wpf中显示树状视图项的上下文菜单?如何仅显示CountryTemplate的关联菜单: <HierarchicalDataTemplate x:Key="DispTemplate"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Path=Label}" Style="{StaticResource TreeText

如何使用分层数据模板在wpf中显示树状视图项的上下文菜单?如何仅显示CountryTemplate的关联菜单:

  <HierarchicalDataTemplate  x:Key="DispTemplate">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding Path=Label}" Style="{StaticResource TreeTextStyle}" ToolTip="{Binding Path=Description}" Tag="{Binding Path=Tag}">
            </TextBlock>
        </StackPanel>
    </HierarchicalDataTemplate>
    <HierarchicalDataTemplate  x:Key="BuildingTemplate"  ItemsSource="{Binding Path=Building}" ItemTemplate="{StaticResource BuildingTemplate}">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding Path=Label}" Style="{StaticResource TreeTextStyle}" ToolTip="{Binding Path=Description}"/>
        </StackPanel>
    </HierarchicalDataTemplate>
    <HierarchicalDataTemplate  x:Key="CityTemplate"  ItemsSource="{Binding Path=City}" ItemTemplate="{StaticResource CityTemplate}">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding Path=Label}" Style="{StaticResource TreeTextStyle}" ToolTip="{Binding Path=Description}"/>
        </StackPanel>
    </HierarchicalDataTemplate>
    <HierarchicalDataTemplate x:Key="CountryTemplate" ItemsSource="{Binding Path=Country}" ItemTemplate="{StaticResource CountryTemplate}">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding Path=RootName}" Style="{StaticResource TreeTextStyle}" ToolTip="{Binding Path=Description}"/>
        </StackPanel>
    </HierarchicalDataTemplate>



如您所见,您可以在HierarchycalDataTemplate的Itemcontainerstyle中添加contextmenu,也可以将contextmenu添加到数据模板中的任何可视子级,例如:

<HierarchicalDataTemplate x:Key="CountryTemplate" ItemsSource="{Binding Path=Country}" ItemTemplate="{StaticResource CountryTemplate}">
    <StackPanel Orientation="Horizontal">
        <StackPanel.ContextMenu>
            <ContextMenu>
                 <MenuItem Header="Header" Command="{Binding Command}"/> <!--This command should be in the data context (each country item)-->
            </ContextMenu>
        </StackPanel.ContextMenu>
        <TextBlock Text="{Binding Path=RootName}" Style="{StaticResource TreeTextStyle}" ToolTip="{Binding Path=Description}"/>
    </StackPanel>
</HierarchicalDataTemplate>

基本上我想到了这个

<HierarchicalDataTemplate  x:Key="ChildTemplate">
            <StackPanel Orientation="Horizontal">
                <StackPanel.ContextMenu>
                    <ContextMenu>
                        <MenuItem Header="Copy" CommandParameter="{Binding CopyTag}">
                        </MenuItem>
                        <MenuItem Header="Paste" CommandParameter="{Binding PasteTag}">
                        </MenuItem>
                        <ContextMenu.ItemContainerStyle>
                            <Style TargetType="MenuItem">
                                <Setter Property="Command" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.CopyPaste}"/>
                            </Style>
                        </ContextMenu.ItemContainerStyle>
                    </ContextMenu>
                </StackPanel.ContextMenu>
                <Image Source="/Images/Child.png" Stretch="None" VerticalAlignment="Center" HorizontalAlignment="Center" Style="{StaticResource TreeIconStyle}"/>
                <TextBlock Text="{Binding Path=Label}" Style="{StaticResource TreeTextStyle}" ToolTip="{Binding Path=Description}" Tag="{Binding Path=Tag}">
                </TextBlock>
            </StackPanel>
        </HierarchicalDataTemplate>


并且具有用于复制和粘贴的单独参数,以便在单个命令中区分复制和粘贴。

上下文菜单不能尽可能干净地工作的原因之一是,默认情况下,它们位于与其他所有内容不同的视觉树中,因此无法找到
数据上下文

关键是创建一个定义上下文菜单的
, 然后将该样式附加到目标元素,该元素将连接上下文 菜单。这会将上下文菜单移动到一个可视化树中,该树与所需的默认
DataContext
对齐

首先,创建样式:

<UserControl.Resources>                                                                                                                        
    <ResourceDictionary>

        <!-- For the context menu to work, we must shift it into a style, which means that the context menu is now in a
        visual tree that is more closely related to the current data context. All we have to do then is set the style, 
        which hooks up the context menu. -->
        <Style x:Key="ContextMenuStyle" TargetType="{x:Type StackPanel}">
            <Setter Property="ContextMenu" Value="{DynamicResource TreeViewContextMenu}"/>
        </Style>
        <ContextMenu x:Key="TreeViewContextMenu">
            <MenuItem Header="Test" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.CmdDisplayDetailsGraph}"/>
        </ContextMenu>

然后,将上下文菜单连接到任何您想要的位置,而不会遇到由不同的视觉树引起的问题

例1:

<HierarchicalDataTemplate DataType="{x:Type snapshot:Details}" ItemsSource="{Binding DetailsList}">
    <StackPanel Orientation="Vertical" Style="{StaticResource ContextMenuStyle}">
        <ContentPresenter Content="{Binding}" ContentTemplate="{Binding View.DefaultDataRowTemplate}" />
</StackPanel>

例2:

<DataTemplate DataType="{x:Type snapshot:InstrumentDetails}">
  <StackPanel Orientation="Vertical" Style="{StaticResource ContextMenuStyle}">                 
      <Grid HorizontalAlignment="Stretch" VerticalAlignment="Center">


如何绑定到viewmodel根目录中定义的命令。到目前为止,FindAncestor方法不起作用。你能给我举个例子吗?在我无法轻松访问视图模型进行绑定的情况下,我尝试使用这个findancestorbinding:Command=“{binding DataContext.Command,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type MainWindow}}”,通常主窗口的DataContext具有根视图模型,还有您需要的命令。由于某些原因,上下文菜单不起作用,因为它不是可视化树的一部分。是的,您是对的,那么您应该从视图模型中发出该命令。可能使用一种消息(mvvm light或您自己实现的)或为所有视图模型层次结构引发事件,这是一种复杂的方法。是的,即使是像XAML这样的小事情也是一种痛苦。我必须想出一些超乎寻常的解决方案。这对我来说非常有效,而且,我喜欢在项目附近定义ContextMenu。这对我来说非常有效。为了避免编译错误,我必须交换块(确保XAML标记
HierarchycalDataTemplate
位于
Style
ContextMenu
标记之后)。它之所以能够工作,是因为将ContextMenu转换为样式将所有内容转换为一个更密切相关的可视树,这意味着可以毫不费力地找到DataContext。
<DataTemplate DataType="{x:Type snapshot:InstrumentDetails}">
  <StackPanel Orientation="Vertical" Style="{StaticResource ContextMenuStyle}">                 
      <Grid HorizontalAlignment="Stretch" VerticalAlignment="Center">