【问题标题】:Checkable MenuItem With Sub Menus带有子菜单的可检查菜单项
【发布时间】:2011-02-25 02:12:34
【问题描述】:

您能否在 WPF 中将顶级设置为可检查的子菜单?我似乎无法让它工作。

<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>

顶级 1 是可检查的,但不显示子级别。有什么想法吗?

【问题讨论】:

    标签: wpf menuitem


    【解决方案1】:

    如果您深入研究MenuItemControlTemplate,您会发现它使用不同的模板,具体取决于它的Role 属性。

    参考:

    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>
    

    似乎默认情况下它可以允许检查或子项。

    要解决此问题,请使用以下代码:

    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>
    

    后面的代码:

    private void MenuItem_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        (sender as MenuItem).IsChecked = !(sender as MenuItem).IsChecked;
    }
    

    我强烈建议将此功能转换/封装成Attached PropertyBehavior

    【讨论】:

    • 这行得通,只是我有实现 IsChecked 内容的子菜单,这会导致级联效果。这是另一个问题。
    • 这是关闭的,但我需要关闭菜单,即像这样操作是实际选择。相反,它仍然坐在那里等待输入...
    【解决方案2】:

    添加到 decyclone 的答案:

    由于执行此操作后菜单仍处于打开状态,如果您希望它关闭,您可以通过在父上下文菜单上设置 IsOpen = false 来关闭菜单:

    private void MenuItem_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) {
        (sender as MenuItem).IsChecked = !(sender as MenuItem).IsChecked; 
        ((sender as MenuItem).Parent as ContextMenu).IsOpen = false;
    } 
    

    【讨论】:

    • 这将一直有效,直到您有多个子菜单。然后你需要走上多个父母。
    • 没错。在我的例子中,我只需要在顶部菜单上使用它。
    【解决方案3】:

    另一种方法是简单地使用 CheckBox 作为 MenuItem 的图标:

    <MenuItem>
        <MenuItem.Icon>
            <CheckBox HorizontalAlignment="Center" VerticalAlignment="Center" IsChecked="{Binding MyCheckProperty}"/>
        </MenuItem.Icon>
        <MenuItem Header="Item1"/>
        <MenuItem Header="Item2"/>
    </MenuItem>
    

    在这种情况下,用户必须单击 CheckBox - 而不仅仅是 MenuItem 上的任何位置 - 以更改状态,而单击其他位置将保持立即打开子菜单的默认行为(可能需要也可能不需要)。此外,这允许三态值。特别是,如果顶层菜单应该作为其所有子菜单的主开关,空状态表示某些子状态已检查,而有些则未检查,则此功能非常好。至于decyclone的回答,除非采取进一步措施,否则菜单将保持打开状态。

    【讨论】:

      猜你喜欢
      • 2011-03-14
      • 2014-02-20
      • 1970-01-01
      • 2014-11-01
      • 2023-03-27
      • 2012-03-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多