问题
Can you have submenus with the top level set to checkable in WPF? I can't seem to get this to work.
<Window.ContextMenu>
<ContextMenu>
<MenuItem Header="Top Level 1" IsCheckable="True" IsChecked="True">
<MenuItem Header="Sub Level" />
<MenuItem Header="Sub Level" />
</MenuItem>
<MenuItem Header="Top Level 2">
<MenuItem Header="Sub Level" />
<MenuItem Header="Sub Level" />
</MenuItem>
</ContextMenu>
</Window.ContextMenu>
Top Level 1 is checkable, but the sub levels don't appear. Any thoughts?
回答1:
If you dig into MenuItem
's ControlTemplate
, you will see that it uses different templates depending on it's Role
property.
Reference:
Menu Styles and Templates
<Style x:Key="{x:Type MenuItem}"
TargetType="{x:Type MenuItem}">
<Setter Property="OverridesDefaultStyle"
Value="True" />
<Style.Triggers>
<Trigger Property="Role"
Value="TopLevelHeader">
<Setter Property="Template"
Value="{StaticResource {x:Static MenuItem.TopLevelHeaderTemplateKey}}" />
<Setter Property="Grid.IsSharedSizeScope"
Value="true" />
</Trigger>
<Trigger Property="Role"
Value="TopLevelItem">
<Setter Property="Template"
Value="{StaticResource {x:Static MenuItem.TopLevelItemTemplateKey}}" />
</Trigger>
<Trigger Property="Role"
Value="SubmenuHeader">
<Setter Property="Template"
Value="{StaticResource {x:Static MenuItem.SubmenuHeaderTemplateKey}}" />
</Trigger>
<Trigger Property="Role"
Value="SubmenuItem">
<Setter Property="Template"
Value="{StaticResource {x:Static MenuItem.SubmenuItemTemplateKey}}" />
</Trigger>
</Style.Triggers>
</Style>
Seems like it can either allow checking or subitems by default.
To workaround that, use following code:
XAML:
<ContextMenu>
<MenuItem Header="Top Level 1"
Mouse.PreviewMouseUp="MenuItem_MouseLeftButtonUp">
<MenuItem Header="Sub Level" />
<MenuItem Header="Sub Level" />
</MenuItem>
<MenuItem Header="Top Level 2">
<MenuItem Header="Sub Level" />
<MenuItem Header="Sub Level" />
</MenuItem>
</ContextMenu>
Code behind:
private void MenuItem_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
(sender as MenuItem).IsChecked = !(sender as MenuItem).IsChecked;
}
I strongly recommend converting/encapsulating this piece of functionality into an Attached Property
or a Behavior
.
回答2:
To add to decyclone's answer:
Since the menu will sit there still open after doing this, and if you want it to close, you can then close the menu by setting IsOpen = false on the parent contextmenu:
private void MenuItem_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) {
(sender as MenuItem).IsChecked = !(sender as MenuItem).IsChecked;
((sender as MenuItem).Parent as ContextMenu).IsOpen = false;
}
来源:https://stackoverflow.com/questions/5112880/checkable-menuitem-with-sub-menus