WPF中的上下文菜单继承

4

我有一个TreeView,其中包含不同类型的项目。项目样式是通过自定义ItemContainerStyleSelector属性定义的。

我的样式都共享一个基本样式,每个样式中只定义了特定于项目的内容。它看起来像这样:

<Style x:Key="BaseStyle" TargetType="{x:Type TreeViewItem}">
...
</Style>

<Style x:Key ="SomeSpecificStyle" TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource BaseStyle}">
   <Setter Property="ContextMenu" Value="{StaticResource NodeContextMenu}"/>
   ...  
</Style>

<Style x:Key ="SomeSpecificStyle" TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource BaseStyle}">
   <Setter Property="ContextMenu" Value="{StaticResource AnotherNodeContextMenu}"/>
   ...  
</Style>

上下文菜单的定义如下:
<ContextMenu x:Key="NodeContextMenu">
  <MenuItem Header="Select Views" Command="{Binding Path=OpenViewsCommand}" />
  ...other specific entries
  <MenuItem Header="Remove" Command="{Binding Path=DocumentRemoveCommand}" />
  ...other entries common for all menus
</ContextMenu>

另一个上下文菜单也应该包含像删除这样的常见项目。每次更改命令属性等都需要复制粘贴进行复制。维护起来很麻烦。有没有一种方法可以定义一个包含常见项目的上下文菜单,然后“派生”特定的上下文菜单?
编辑:我在这个线程的提示下找到了解决方案:我定义了一个包含常见项目的集合,并在定义菜单时使用组合集合来包括新项目和常见项目集合。
<CompositeCollection x:Key="CommonItems"> 
  <MenuItem Header="Remove" Command="{Binding Path=DocumentRemoveCommand}">
  ....Other common stuff
</CompositeCollection>

<ContextMenu x:Key="NodeContextMenu">
  <ContextMenu.ItemsSource>
    <CompositeCollection>
      <MenuItem Header="Select Views" Command="{Binding Path=OpenViewsCommand}" />
      <CollectionContainer Collection="{StaticResource CommonItems}" />
    </CompositeCollection>
  </ContextMenu.ItemsSource>
</ContextMenu>

4
最好您发表自己的答案,而不是将答案编辑到问题中。 - LarsTech
1个回答

5
您可以将项目声明为资源并引用它们:
<Some.Resources>
    <MenuItem x:Key="mi_SelectViews" x:Shared="false"
              Header="Select Views" Command="{Binding Path=OpenViewsCommand}" />
    <MenuItem x:Key="mi_Remove" x:Shared="false"
              Header="Remove" Command="{Binding Path=DocumentRemoveCommand}" />
</Some.Resources>

<ContextMenu x:Key="NodeContextMenu">
  <StaticResource ResourceKey="mi_SelectViews" />
  ...other specific entries
  <StaticResource ResourceKey="mi_Remove" />
  ...other entries common for all menus
</ContextMenu>

(x:Shared 很重要)


另一种可能性是通过对象模型方法生成 MenuItems,只需将 ItemsSource 绑定到某些对象列表,这些对象模拟了 MenuItem 的功能(例如用于子项、标题和命令的属性),然后您可以创建一个 Remove 模型,该模型可以成为多个列表的一部分。


这比原始解决方案要好,但仍可能会引起麻烦,因为如果添加新项目或删除条目,则需要进行复制。 - Petr Osipov
@PetrOsipov:怎么会呢?你只有多个引用,而且你至少会有一个。 - H.B.
好的,我希望有这样一个东西:BaseMenu 包含一打常用项,只需编写一次。每个子菜单都引用基础菜单,继承其项,并仅添加节点特定内容。 - Petr Osipov
@PetrOsipov:嗯,我认为这并不容易实现,特别是因为您显然想在现有项目之间添加项目。 - H.B.
将特定项目放在菜单顶部并将常见项目放在底部分组,这样做应该没有问题... - Petr Osipov
@PetrOsipov:那我建议使用对象模型方法,例如,你可以使用CompositeCollections将常规列表与新项目合并。 - H.B.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接