Checkable MenuItem With Sub Menus

 ̄綄美尐妖づ 提交于 2020-01-12 15:50:28

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!