WPF:修改MenuItem的IsSubmenuOpen颜色且保留下拉弹窗功能
问题描述
我正在学习复刻Windows平台上IntelliJ的标题栏菜单,WPF MenuItem默认的颜色行为如下:
- 处于
IsMouseOver且未触发IsSubmenuOpen时,背景为低透明度蓝色 - 触发
IsSubmenuOpen时,背景为低透明度蓝色
我想要改成IntelliJ的样式:
- 处于
IsMouseOver且未触发IsSubmenuOpen时,无颜色变化 - 触发
IsSubmenuOpen时,背景为深蓝色 - 触发
IsSubmenuOpen时,前景为白色
我找到了一段能实现颜色效果的代码,但它会禁用MenuItem打开下拉子菜单的功能,代码如下:
<Style x:Key="TitleBarMenuItem" TargetType="{x:Type MenuItem}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type MenuItem}"> <Border Background="{TemplateBinding Background}"> <ContentPresenter Content="{TemplateBinding Header}" Margin="35 5 10 5" /> </Border> <ControlTemplate.Triggers> <Trigger Property="IsSubmenuOpen" Value="True"> <Setter Property="Foreground" Value="White"/> <Setter Property="Background" Value="#2675BF"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>
请问如何在实现上述颜色变化的同时,保留MenuItem的下拉功能?
解决方案
问题出在你自定义的ControlTemplate里——默认的MenuItem模板包含了触发子菜单展开的Popup控件和交互逻辑,完全重写模板后删掉这些关键部分,就会导致子菜单无法打开。
以下两种方式可以实现需求,同时保留下拉功能:
方式一:仅修改触发器(推荐)
无需重写整个模板,直接基于默认样式添加触发器覆盖颜色行为即可,这种方式能完整保留默认交互逻辑:
<Style x:Key="TitleBarMenuItem" TargetType="{x:Type MenuItem}" BasedOn="{StaticResource {x:Type MenuItem}}"> <Style.Triggers> <!-- 取消MouseOver状态下的背景变化 --> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="Background" Value="Transparent"/> <Setter Property="BorderBrush" Value="Transparent"/> </Trigger> <!-- 设置IsSubmenuOpen状态下的样式 --> <Trigger Property="IsSubmenuOpen" Value="True"> <Setter Property="Foreground" Value="White"/> <Setter Property="Background" Value="#2675BF"/> </Trigger> </Style.Triggers> </Style>
方式二:重写模板但保留子菜单控件
如果一定要重写模板,必须保留名为PART_Popup的控件(WPF MenuItem依赖该命名控件处理子菜单展开逻辑),完整示例如下:
<Style x:Key="TitleBarMenuItem" TargetType="{x:Type MenuItem}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type MenuItem}"> <Grid> <!-- 主内容显示区域 --> <Border x:Name="Border" Background="{TemplateBinding Background}" Padding="35 5 10 5"> <ContentPresenter Content="{TemplateBinding Header}" /> </Border> <!-- 子菜单Popup(必须保留PART_Popup命名) --> <Popup x:Name="PART_Popup" AllowsTransparency="True" Placement="Bottom" IsOpen="{Binding IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}" Focusable="False"> <Border x:Name="SubmenuBorder" Background="#FFFFFF" BorderThickness="1" BorderBrush="#E0E0E0"> <ScrollViewer x:Name="SubmenuScrollViewer" CanContentScroll="True"> <ItemsPresenter x:Name="ItemsPresenter" /> </ScrollViewer> </Border> </Popup> </Grid> <ControlTemplate.Triggers> <!-- 取消MouseOver状态下的背景变化 --> <Trigger Property="IsMouseOver" Value="True"> <Setter TargetName="Border" Property="Background" Value="Transparent"/> </Trigger> <!-- 设置IsSubmenuOpen状态下的样式 --> <Trigger Property="IsSubmenuOpen" Value="True"> <Setter TargetName="Border" Property="Background" Value="#2675BF"/> <Setter Property="Foreground" Value="White"/> </Trigger> <!-- 没有子项时隐藏Popup --> <Trigger Property="HasItems" Value="False"> <Setter TargetName="PART_Popup" Property="Visibility" Value="Collapsed"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>
内容的提问来源于stack exchange,提问作者Jack J
相关产品推荐
相关产品推荐

