首页 > 解决方案 > WPF 子菜单项不显示在顶层菜单项下

问题描述

我正在尝试在我的 WPF 项目中创建一个基本的菜单系统。我已经通过App.xaml. 当我单击顶级菜单项时,它的子菜单项不显示。

我怀疑 ContentPresenter 应该已经被重构了,但是我找不到任何关于正确配置的内容。

我应该重构什么以使这种简单的样式与子菜单项一起使用?

中的附加样式App.xaml

<Style TargetType="{x:Type Menu}">
                <Setter Property="Foreground" Value="#ffffff"/>
                <Setter Property="Background" Value="#da4148"/>
            </Style>
            <Style TargetType="{x:Type MenuItem}">
                <Setter Property="Foreground" Value="#ffffff"/>
                <Setter Property="Background" Value="#da4148"/>

                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type MenuItem}">
                            <Border x:Name="Border" Background="{TemplateBinding Background}"
                                    SnapsToDevicePixels="True" Uid="Border_38" Margin="0,10,0,0" Padding="3">

                                <ContentPresenter x:Name="ContentPresenter" Content="{TemplateBinding Header}"
                                                  Grid.Column="1" ContentSource="Header" Margin="{TemplateBinding Padding}"/>
                            </Border>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsHighlighted" Value="True">
                                    <Setter Property="Background" TargetName="Border" Value="#ffffff"/>
                                    <Setter Property="TextBlock.Foreground" TargetName="Border" Value="#da4148"/>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>

菜单本身:

<DockPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3">
            <Menu DockPanel.Dock="Top" Margin="0" Grid.ColumnSpan="2">
                <MenuItem Command="{Binding OpenHomePageCommand}">
                    <MenuItem.Header>
                        <StackPanel>
                            <Image Width="20" Height="20" Source="pack://application:,,,/Resources/Images/home.png" />
                            <ContentPresenter Content="Home" />
                        </StackPanel>
                    </MenuItem.Header>
                </MenuItem>
                <MenuItem Header="{DynamicResource File}" Height="40">
                    <MenuItem Header="{DynamicResource SaveFile}" Command="{Binding SaveFileCommand}" CommandParameter="{Binding FileDisplayerViewModel.DisplayedFile}" Height="30"/>
                    <MenuItem Header="{DynamicResource Exit}" Command="{Binding CloseApplicationCommand}" Height="30"/>
                </MenuItem>
                <MenuItem Header="{DynamicResource Settings}" Height="40">
                    <MenuItem Header="{DynamicResource Watermark}" Command="{Binding ShowWatermarkWindowCommand}" Height="30"/>

                    <MenuItem Header="{DynamicResource Language}" Height="30">
                        <MenuItem Header="{DynamicResource English}" Command="{Binding SetEnglishLanguageCommand}" Height="30"/>
                        <MenuItem Header="{DynamicResource Hungarian}" Command="{Binding SetHungarianLanguageCommand}" Height="30"/>
                    </MenuItem>
                    <MenuItem Header="{DynamicResource ApplicationProperties}" Command="{Binding ShowApplicationPropertiesWindowCommand}" Height="30"/>
                </MenuItem>
                <MenuItem Header="{DynamicResource Help}" Height="40">
                    <MenuItem Header="{DynamicResource Help}" Height="30" Command="{Binding OpenHelpWebsiteCommand}"/>
                    <MenuItem Header="{DynamicResource About}" Height="30" Command="{Binding AboutCommand}"/>
                </MenuItem>
            </Menu>
        </DockPanel>

当我将鼠标移到 MenuItem 上时,悬停样式有效,但未显示子菜单项:

未显示子菜单项

标签: c#wpfmenumenuitemsubmenu

解决方案


Menu是一个完全由MenuItem元素组成的树结构。它有一个根节点(标题项)和子项(子项)。如果子项目也是一个节点(可以有孩子),那么这个节点也必须是一个标题。标头也是一个MenuItem但不同的模板。它有一个popup包含显示子项的项目面板。

现在,您正在使用一个隐式Style,它也覆盖所有标题项并将其转换为可以容纳子项且不能展开(无弹出窗口)的普通子项。因此,您基本上缺少Popup包含子菜单项的 a 。如果您还想覆盖标题模板,则必须添加类似以下内容:

<!-- TopLevelHeader -->
<ControlTemplate x:Key="{x:Static MenuItem.TopLevelHeaderTemplateKey}"
                 TargetType="{x:Type MenuItem}">
  <Border x:Name="Border">
    <Grid>
      <ContentPresenter Margin="6,3,6,3"
                        ContentSource="Header"
                        RecognizesAccessKey="True" />
      <Popup x:Name="Popup"
             Placement="Bottom"
             IsOpen="{TemplateBinding IsSubmenuOpen}"
             AllowsTransparency="True"
             Focusable="False"
             PopupAnimation="Fade">
        <Border x:Name="SubmenuBorder"
                SnapsToDevicePixels="True"
                BorderThickness="1"
                Background="{DynamicResource MenuPopupBrush}">
          <Border.BorderBrush>
            <SolidColorBrush Color="{DynamicResource BorderMediumColor}" />
          </Border.BorderBrush>
          <ScrollViewer CanContentScroll="True"
                        Style="{StaticResource MenuScrollViewer}">
            <StackPanel IsItemsHost="True"
                        KeyboardNavigation.DirectionalNavigation="Cycle" />
          </ScrollViewer>
        </Border>
      </Popup>
    </Grid>
  </Border>
  <ControlTemplate.Triggers>
    <Trigger Property="IsSuspendingPopupAnimation"
             Value="true">
      <Setter TargetName="Popup"
              Property="PopupAnimation"
              Value="None" />
    </Trigger>
    <Trigger Property="IsHighlighted"
             Value="true">
      <Setter TargetName="Border"
              Property="BorderBrush"
              Value="Transparent" />
      <Setter Property="Background"
              TargetName="Border">
        <Setter.Value>
          <LinearGradientBrush StartPoint="0,0"
                               EndPoint="0,1">
            <LinearGradientBrush.GradientStops>
              <GradientStopCollection>
                <GradientStop Color="{StaticResource ControlLightColor}" />
                <GradientStop Color="{StaticResource ControlMouseOverColor}"
                              Offset="1.0" />
              </GradientStopCollection>
            </LinearGradientBrush.GradientStops>
          </LinearGradientBrush>

        </Setter.Value>
      </Setter>
    </Trigger>
    <Trigger SourceName="Popup"
             Property="AllowsTransparency"
             Value="True">
      <Setter TargetName="SubmenuBorder"
              Property="CornerRadius"
              Value="0,0,4,4" />
      <Setter TargetName="SubmenuBorder"
              Property="Padding"
              Value="0,0,0,3" />
    </Trigger>
    <Trigger Property="IsEnabled"
             Value="False">
      <Setter Property="Foreground">
        <Setter.Value>
          <SolidColorBrush Color="{StaticResource DisabledForegroundColor}" />
        </Setter.Value>
      </Setter>
    </Trigger>
  </ControlTemplate.Triggers>
</ControlTemplate>

或者,您可以MenuItem明确您的样式并将其直接应用于子菜单项。

但推荐的方法是使用正在使用的资源模板键Menu。只需定义一个ControlTemplate and override the template resource key (e.g.:TopLevelHeaderTemplateKey orSubmenuHeaderTemplateKey`)

标题项:

<ControlTemplate x:Key="{x:Static MenuItem.TopLevelHeaderTemplateKey}"
                 TargetType="{x:Type MenuItem}">
</ControlTemplate>

您可以在Microsoft Docs中找到完整的默认模板。它显示了如何覆盖所有四个模板资源键。您可以修改它们以满足您的要求。

每个资源键映射到一个MenuItemRole(例如TopLevelHeader)。使用资源键描述布局,使用角色描述行为。


推荐阅读