如何在 wpf 的分层数据模板中显示树视图项的上下文菜单
Posted
技术标签:
【中文标题】如何在 wpf 的分层数据模板中显示树视图项的上下文菜单【英文标题】:How to display context menu for treeview item in a hierarchial data template in wpf 【发布时间】:2012-11-05 10:31:17 【问题描述】:如何使用分层数据模板在 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>
【问题讨论】:
【参考方案1】:您还可以将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>
【讨论】:
如何绑定到视图模型根目录中定义的命令。到目前为止 FindAncestor 方法不起作用。你能给我举个例子吗? 在我无法轻松访问视图模型以进行绑定的情况下,我尝试使用此 FindAncestor 绑定:Command="Binding DataContext.Command, RelativeSource=RelativeSource FindAncestor, AncestorType= x:Type MainWindow",一般主窗口的datacontext有根视图模型,有你想要的命令。 这不适用于上下文菜单,因为它不是可视化树的一部分。 是的,你是对的,那么你应该从你的视图模型中发出命令。也许使用一种消息(mvvm light 或由您自己实现)或为您的所有视图模型层次结构引发事件,这是一种复杂的方式。 是的,即使是像这样的小东西 XAML 也是一个真正的痛苦。我必须想出超出正常范围的解决方案。【参考方案2】:上下文菜单无法正常工作的原因之一是,默认情况下,它们位于与其他所有内容不同的可视化树中,因此无法找到 DataContext
。
关键的见解是创建一个定义上下文菜单的
<Style>
, 然后将该样式附加到目标元素,该元素连接上下文 菜单。 这会将上下文菜单转换为一个可视树,该树与您想要的默认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">
【讨论】:
【参考方案3】:<HierarchicalDataTemplate x:Key="CountryTemplate" ItemsSource="Binding Path=Country" ItemContainerStyle="StaticResource CountryTemplateItemContainerStyle" ItemTemplate="StaticResource CountryTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Binding Path=RootName" Style="StaticResource TreeTextStyle" ToolTip="Binding Path=Description" />
</StackPanel>
</HierarchicalDataTemplate>
<Style x:Key="CountryTemplateItemContainerStyle" TargetType="x:Type TreeViewItem">
<Setter Property="ContextMenu" Value="DynamicResource TreeViewContextMenu"/>
</Style>
<ContextMenu x:Key="TreeViewContextMenu">
<MenuItem .../>
</ContextMenu>
如您所见,您可以在 HierarchicalDataTemplate 的 Itemcontainerstyle 中添加上下文菜单
【讨论】:
这对我来说非常有用,而且,我喜欢 ContextMenu 是如何在项目附近定义的。 这对我有用。为了避免编译错误,我不得不交换块(确保 XAML 标记HierarchicalDataTemplate
在 Style
和 ContextMenu
标记之后)。它起作用的原因是因为将 ContextMenu 转换为样式会将所有内容转换为更密切相关的可视化树,这意味着可以轻松找到 DataContext。【参考方案4】:
基本上我想出了这个
<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>
并具有单独的复制和粘贴参数,以区分单个命令中的复制和粘贴。
【讨论】:
以上是关于如何在 wpf 的分层数据模板中显示树视图项的上下文菜单的主要内容,如果未能解决你的问题,请参考以下文章