如何为WPF MenuItem添加子菜单箭头显示功能?
我正在学习WPF结合PowerShell使用,已经实现了自定义MenuItem控件,保留了原生MenuItem的全部功能,但目前无法为带有子菜单的菜单项(包括非顶级父项)显示箭头。
当前效果

所需效果

原实现代码
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Project" Width="400" Height="520" ResizeMode="CanMinimize" WindowStartupLocation="CenterScreen" Background="#191919"> <Window.Resources> <Style TargetType="MenuItem"> <Setter Property="Foreground" Value="#E6E6E6"/> <Setter Property="Background" Value="#4C4C4C"/> <Setter Property="Padding" Value="3"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="MenuItem"> <Grid Background="{TemplateBinding Background}"> <Border x:Name="Border" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}"> <TextBlock x:Name="MenuItemText" Text="{Binding Path=Header, RelativeSource={RelativeSource TemplatedParent}}" HorizontalAlignment="Left" VerticalAlignment="Center" Foreground="{TemplateBinding Foreground}"/> </Border> <Popup x:Name="SubMenuPopup" IsOpen="{TemplateBinding IsSubmenuOpen}" Placement="Right"> <Grid Background="{TemplateBinding Background}"> <ItemsPresenter/> </Grid> </Popup> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsSubmenuOpen" Value="True"> <Setter TargetName="MenuItemText" Property="Foreground" Value="#E6E6E6"/> <Setter TargetName="Border" Property="Background" Value="#2B2B2B"/> </Trigger> <Trigger Property="IsMouseOver" Value="True"> <Setter TargetName="MenuItemText" Property="Foreground" Value="#2B2B2B"/> <Setter TargetName="Border" Property="Background" Value="#E6E6E6"/> </Trigger> <Trigger Property="IsEnabled" Value="False"> <Setter TargetName="MenuItemText" Property="Foreground" Value="#7F7F7F"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </Window.Resources> <Grid> <Menu HorizontalAlignment="Right" VerticalAlignment="Bottom"> <MenuItem Header=" Apoiar "/> <MenuItem Header=" Sobre "> <MenuItem Header="EmLogs"/> <MenuItem Header="Licenças de Terceiros"> <MenuItem Header="BrowserDownloadsView"/> <MenuItem Header="BrowsingHistoryView"/> <MenuItem Header="CSVFileView"/> <MenuItem Header="Everything"/> <MenuItem Header="ExecutedProgramsList"/> <MenuItem Header="InstalledDriversList"/> <MenuItem Header="LastActivityView"/> <MenuItem Header="ProcessExplorer" IsEnabled="False"/> <MenuItem Header="RegScanner"/> <MenuItem Header="ShellBagsView"/> <MenuItem Header="System Informer"> <MenuItem Header="Licença"/> <MenuItem Header="Licenças de Terceiros"/> </MenuItem> <MenuItem Header="TaskSchedulerView"/> <MenuItem Header="WebBrowserBookmarksView"/> <MenuItem Header="WhatInStartup"/> <MenuItem Header="WinDefLogView"/> </MenuItem> </MenuItem> </Menu> </Grid> </Window>
解决方案
要实现子菜单箭头显示,需在ControlTemplate中添加箭头元素,并通过触发器控制其仅在菜单项有子项(HasItems=True)时显示。具体修改如下:
- 将原Border内的TextBlock替换为DockPanel,同时添加箭头元素
- 添加触发器,根据
HasItems属性控制箭头的可见性 - 同步箭头在不同状态下的颜色,保持与整体风格一致
修改后的完整Style代码
<Style TargetType="MenuItem"> <Setter Property="Foreground" Value="#E6E6E6"/> <Setter Property="Background" Value="#4C4C4C"/> <Setter Property="Padding" Value="3"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="MenuItem"> <Grid Background="{TemplateBinding Background}"> <Border x:Name="Border" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}"> <!-- 用DockPanel承载文本和箭头 --> <DockPanel HorizontalAlignment="Stretch"> <TextBlock x:Name="MenuItemText" Text="{Binding Path=Header, RelativeSource={RelativeSource TemplatedParent}}" HorizontalAlignment="Left" VerticalAlignment="Center" Foreground="{TemplateBinding Foreground}" DockPanel.Dock="Left"/> <!-- 子菜单箭头 --> <TextBlock x:Name="SubmenuArrow" Text=">" HorizontalAlignment="Right" VerticalAlignment="Center" Foreground="{TemplateBinding Foreground}" Visibility="Collapsed"/> </DockPanel> </Border> <Popup x:Name="SubMenuPopup" IsOpen="{TemplateBinding IsSubmenuOpen}" Placement="Right"> <Grid Background="{TemplateBinding Background}"> <ItemsPresenter/> </Grid> </Popup> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsSubmenuOpen" Value="True"> <Setter TargetName="MenuItemText" Property="Foreground" Value="#E6E6E6"/> <Setter TargetName="Border" Property="Background" Value="#2B2B2B"/> <Setter TargetName="SubmenuArrow" Property="Foreground" Value="#E6E6E6"/> </Trigger> <Trigger Property="IsMouseOver" Value="True"> <Setter TargetName="MenuItemText" Property="Foreground" Value="#2B2B2B"/> <Setter TargetName="Border" Property="Background" Value="#E6E6E6"/> <Setter TargetName="SubmenuArrow" Property="Foreground" Value="#2B2B2B"/> </Trigger> <Trigger Property="IsEnabled" Value="False"> <Setter TargetName="MenuItemText" Property="Foreground" Value="#7F7F7F"/> <Setter TargetName="SubmenuArrow" Property="Foreground" Value="#7F7F7F"/> </Trigger> <!-- 关键触发器:有子项时显示箭头 --> <Trigger Property="HasItems" Value="True"> <Setter TargetName="SubmenuArrow" Property="Visibility" Value="Visible"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>
说明:
- 用DockPanel实现文本左对齐、箭头右对齐的布局,保证菜单排版合理
- 通过
HasItems触发器精准控制箭头显示,只有包含子菜单的菜单项才会展示箭头 - 同步箭头在鼠标悬停、菜单展开、禁用状态下的颜色,保持与文本风格统一
内容的提问来源于stack exchange,提问作者Humberto Freitas
相关产品推荐
相关产品推荐

