在以下WPF ListView
中,我创建了两个ContextMenus
:一个用于ListView本身,一个用于每个特定列表项。它看起来像这样:
<ListView ItemsSource="{Binding Path=MyListData}">
<ListView.ContextMenu>
<ContextMenu> <!-- menu for the entire list -->
<MenuItem Header="New Item"/>
<MenuItem Header="Sort by">
<MenuItem Header="Name"/>
<MenuItem Header="Author"/>
<MenuItem Header="Date"/>
</MenuItem>
</ContextMenu>
</ListView.ContextMenu>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu> <!-- menu for a specific item -->
<MenuItem Header="Edit"/>
<MenuItem Header="Remove"/>
<Separator/> <!-- note how the following is basically the same as the other menu -->
<MenuItem Header="New Item"/>
<MenuItem Header="Sort by">
<MenuItem Header="Name"/>
<MenuItem Header="Author"/>
<MenuItem Header="Date"/>
</MenuItem>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<!-- ListView content -->
</ListView.View>
</ListView>
这是有效的,但正如您所看到的,第一个Contextmenu的内容将作为第二个内容的一部分重用。这是因为当用户右键单击某个项而不是空白空间时,我希望一般选项(New Item / Sort by)也可用。由于我计划不止一次使用这种通用结构,我可以想象这会变得相当混乱,尤其是考虑到所有必要的命令绑定时。
我尝试在DataTemplate
中定义<ListView.Resources>
,如类似问题的答案中所述,但这不起作用,因为看似独立的MenuItem
不能包含在模板中。如果我在模板中包含<ContextMenu>
标记,则会出现运行时异常,因为ContextMenu
无法生活在另一个ContextMenu
内。
有没有办法创建通常需要特定父元素的可重用代码片段?某种在编译时评估的模板?我想要的只是更易于维护的代码。
答案 0 :(得分:2)
你可以这样做:
<Window.Resources>
<MenuItem x:Key="newItem" Header="New Item" Command="{x:Static ApplicationCommands.New}" x:Shared="False" />
<MenuItem x:Key="sortBy" Header="Sort by" x:Shared="False">
<MenuItem Header="Name" Click="SortByNameClicked"/>
<MenuItem Header="Author"/>
<MenuItem Header="Date"/>
</MenuItem>
</Window.Resources>
<ListView ItemsSource="{Binding Path=MyListData}">
<ListView.ContextMenu>
<ContextMenu>
<!-- menu for the entire list -->
<StaticResource ResourceKey="newItem" />
<StaticResource ResourceKey="sortBy" />
</ContextMenu>
</ListView.ContextMenu>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<!-- menu for a specific item -->
<MenuItem Header="Edit"/>
<MenuItem Header="Remove"/>
<Separator/>
<StaticResource ResourceKey="newItem" />
<StaticResource ResourceKey="sortBy" />
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
注意x:Shared="false"
属性。它的作用是使每个对此资源的引用都能创建新副本。默认情况下,重用相同的资源实例,但这不适合我们的场景,因为我们需要不同菜单的不同实例(否则会抱怨同一项不能是多个父项的子项)。
您可以照常在这些项目上定义命令绑定和点击事件(如您所见)。