news 2026/5/17 4:26:19

WPF 为 ContextMenu 使用 Fluent 风格的亚克力材质特效

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
WPF 为 ContextMenu 使用 Fluent 风格的亚克力材质特效

WPF 为 ContextMenu 使用 Fluent 风格的亚克力材质特效

控件名:ContextMenu

作 者:WPFDevelopersOrg -TwilightLemon

原文链接[1]:https://www.cnblogs.com/TwilightLemon/p/19241723

书接上回,我们的Fluent WPF的版图已经完成了,先来看看效果图 (Win11),以下xaml代码:

<TextBlock.ContextMenu> <ContextMenu> <MenuItem Header="Menu Item 1" Icon="Cd" InputGestureText="aa?" /> <MenuItem Header="Menu Item 2" > <MenuItem Header="Child Item 1" Icon="Ab" /> <MenuItem Header="Child Item 2" Icon="Ad" /> <MenuItem Header="Child Item 3" IsCheckable="True" IsChecked="True"/> </MenuItem> <MenuItem Header="Menu Item 3" Icon="cd" /> </ContextMenu> </TextBlock.ContextMenu>


(由于我的Win10虚拟机坏了,暂时没有测试)

前面的工作已经解决了让任意窗口支持Acrylic材质的问题,本文重点介绍ContentMenuMenuItem的样式适配和实现。

本文的 Demo[2]

一、为什么需要一个新的ContextMenuMenuItem样式

如果你直接给ContextMenu应用WindowMaterial特效,可能会出现以下丑陋的效果:

或者:

原因在于古老的ContextMenuMenuItem样式并不能通过简单修改Background实现我们想要的布局和交互效果。

二、ContextMenuMenuItem的结构
1.ContextMenu的结构

ContextMenu直观上看是一个Popup,但它的控件模板并不包含Popup,而是直接指定内部元素(包含一个ScrollViewerStackPanel)。因此不能从控件模板中替换Popup为自定义的FluentPopup,需要使用其他手段让其内部Popup也支持Acrylic材质(见下文)。

2.MenuItem的四种形态

在示例代码仓库中展示了较为完整的Menu相关的结构:

MenuItem根据其在菜单树中的位置,通过Role属性分为四种形态。我们在Style.Triggers中分别为它们指定了不同的模板:

  • TopLevelHeader: 顶级菜单项,且包含子菜单Popup(例如菜单栏上的"File")。

  • TopLevelItem: 顶级菜单项,不含子菜单(例如菜单栏上的"Help")。

  • SubmenuHeader: 子菜单项,且包含下一级子菜单Popup

  • SubmenuItem: 子菜单项,不含子菜单(叶子节点)。其模板主要处理图标、文字、快捷键的布局。

三、重写Menu相关控件模板和样式
1.ContextMenu样式

ContextMenu的样式主要参考了.NET 9自带的Fluent样式,并作了一些调整以适配Acrylic材质。主要目的是覆盖原始模板的Icon部分白框和分割线:


因为我们的WindowMaterial已经为窗口自动附加上圆角、阴影和亚克力材质的DWM效果,所以我们只需要将ContextMenu的背景设置为透明,并移除不必要的边框和分割线即可。
此外,还添加了弹出动画(是在Popup内部做的,并非对window,效果可能不会很理想)。

2.MenuItem样式

MenuItem的样式主要处理了图标、文字、快捷键的布局,并根据不同的角色(TopLevelHeaderTopLevelItemSubmenuHeaderSubmenuItem)应用不同的模板。

  • TopLevelHeader: 只包含IconHeader,以及弹出的Popup,只需要替换为自定义的FluentPopup即可。

  • TopLevelItem: 只包含 Icon 和 Header ,无 Popup。

  • SubmenuHeader: 包含IconHeaderChevron图标(这里就是一个展开的箭头图标,但是官方叫做雪佛龙..?),以及弹出的Popup,同样替换为FluentPopup

  • SubmenuItem: 叶子节点,包含IconHeaderInputGestureText。 其模板主要处理图标、文字、快捷键的布局。

菜单项主要分为三个部分:Icon 图标Header文字和最右侧的提示文字或展开箭头图标。只需要保持三个部分的布局对其即可。如果IsCheckableTrue,则Icon部分被自定义图标占据(√, 当IsCheckedTrue时)。

以下是完整的资源字典,包含了完整的注释。

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WindowEffectTest" xmlns:sys="clr-namespace:System;assembly=mscorlib"> <!-- 菜单边框内边距 --> <Thickness x:Key="MenuBorderPadding">0,3,0,3</Thickness> <!-- 菜单项外边距 --> <Thickness x:Key="MenuItemMargin">4,1</Thickness> <!-- 菜单项内容内边距 --> <Thickness x:Key="MenuItemContentPadding">10,6</Thickness> <!-- 顶级菜单项外边距 --> <Thickness x:Key="TopLevelItemMargin">4</Thickness> <!-- 顶级菜单项内容边距 --> <Thickness x:Key="TopLevelContentMargin">10</Thickness> <!-- 菜单圆角半径 --> <CornerRadius x:Key="MenuCornerRadius">4</CornerRadius> <!-- 顶级菜单圆角半径 --> <CornerRadius x:Key="TopLevelCornerRadius">6</CornerRadius> <!-- 菜单动画持续时间 --> <Duration x:Key="MenuAnimationDuration">0:0:0.167</Duration> <!-- 复选标记图标路径数据 --> <PathGeometry x:Key="CheckGraph"> M392.533333 806.4L85.333333 503.466667l59.733334-59.733334 247.466666 247.466667L866.133333 213.333333l59.733334 59.733334L392.533333 806.4z </PathGeometry> <!-- 前进箭头图标路径数据(用于子菜单指示器) --> <PathGeometry x:Key="ForwardGraph"> M283.648 174.081l57.225-59.008 399.479 396.929-399.476 396.924-57.228-59.004 335.872-337.92z </PathGeometry> <!-- 菜单项ScrollViewer样式 --> <Style x:Key="MenuItemScrollViewerStyle" BasedOn="{StaticResource {x:Type ScrollViewer}}" TargetType="{x:Type ScrollViewer}"> <Setter Property="HorizontalScrollBarVisibility" Value="Disabled" /> <Setter Property="VerticalScrollBarVisibility" Value="Auto" /> </Style> <!-- 默认集合焦点视觉样式 得到键盘焦点时显示 --> <Style x:Key="DefaultCollectionFocusVisualStyle"> <Setter Property="Control.Template"> <Setter.Value> <ControlTemplate> <Rectangle Margin="4,0" RadiusX="4" RadiusY="4" SnapsToDevicePixels="True" Stroke="{DynamicResource AccentColor}" StrokeThickness="2" /> </ControlTemplate> </Setter.Value> </Setter> </Style> <!-- 默认上下文菜单样式 --> <Style x:Key="DefaultContextMenuStyle" TargetType="{x:Type ContextMenu}"> <Setter Property="MinWidth" Value="140" /> <Setter Property="Padding" Value="0" /> <Setter Property="Margin" Value="0" /> <Setter Property="HasDropShadow" Value="False" /> <Setter Property="Grid.IsSharedSizeScope" Value="True" /> <Setter Property="Popup.PopupAnimation" Value="None" /> <Setter Property="SnapsToDevicePixels" Value="True" /> <Setter Property="OverridesDefaultStyle" Value="True" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ContextMenu}"> <Border x:Name="Border" Padding="{StaticResource MenuBorderPadding}" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> <!-- 用于动画的转换变换 --> <Border.RenderTransform> <TranslateTransform /> </Border.RenderTransform> <ScrollViewer CanContentScroll="True" Style="{StaticResource MenuItemScrollViewerStyle}"> <!-- 菜单项容器 --> <StackPanel ClipToBounds="True" IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Cycle" Orientation="Vertical" /> </ScrollViewer> </Border> <ControlTemplate.Triggers> <!-- 菜单打开时的动画效果 --> <Trigger Property="IsOpen" Value="True"> <Trigger.EnterActions> <BeginStoryboard> <Storyboard> <!-- Y轴平移动画:从-45向下滑入到0 --> <DoubleAnimation Storyboard.TargetName="Border" Storyboard.TargetProperty="(Border.RenderTransform).(TranslateTransform.Y)" From="-45" To="0" Duration="{StaticResource MenuAnimationDuration}"> <DoubleAnimation.EasingFunction> <CircleEase EasingMode="EaseOut" /> </DoubleAnimation.EasingFunction> </DoubleAnimation> </Storyboard> </BeginStoryboard> </Trigger.EnterActions> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> <!-- 顶级菜单项头部模板(带子菜单) --> <ControlTemplate x:Key="{x:Static MenuItem.TopLevelHeaderTemplateKey}" TargetType="{x:Type MenuItem}"> <Border x:Name="Border" Margin="{StaticResource TopLevelItemMargin}" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="{StaticResource TopLevelCornerRadius}"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <!-- 菜单项内容区域 --> <Grid Margin="{StaticResource TopLevelContentMargin}"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <!-- 菜单项图标 --> <ContentPresenter x:Name="Icon" Grid.Column="0" Margin="0,0,6,0" VerticalAlignment="Center" Content="{TemplateBinding Icon}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" /> <!-- 菜单项标题 --> <ContentPresenter x:Name="HeaderPresenter" Grid.Column="1" Margin="{TemplateBinding Padding}" VerticalAlignment="Center" ContentSource="Header" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" TextElement.Foreground="{TemplateBinding Foreground}" /> </Grid> <!-- 子菜单弹出窗口(使用自定义FluentPopup) --> <local:FluentPopup x:Name="PART_Popup" Grid.Row="1" Grid.Column="0" Focusable="False" HorizontalOffset="-12" IsOpen="{TemplateBinding IsSubmenuOpen}" Placement="Bottom" PlacementTarget="{Binding ElementName=Border}" PopupAnimation="None" VerticalOffset="1"> <Grid x:Name="SubmenuBorder" Background="{DynamicResource PopupWindowBackground}" SnapsToDevicePixels="True"> <!-- 子菜单动画变换 --> <Grid.RenderTransform> <TranslateTransform /> </Grid.RenderTransform> <ScrollViewer Padding="{StaticResource MenuBorderPadding}" CanContentScroll="True" Style="{StaticResource MenuItemScrollViewerStyle}"> <Grid> <!-- 子菜单项呈现器 --> <ItemsPresenter x:Name="ItemsPresenter" Grid.IsSharedSizeScope="True" KeyboardNavigation.DirectionalNavigation="Cycle" KeyboardNavigation.TabNavigation="Cycle" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" /> </Grid> </ScrollViewer> </Grid> </local:FluentPopup> </Grid> </Border> <ControlTemplate.Triggers> <!-- 无图标时隐藏图标区域 --> <Trigger Property="Icon" Value="{x:Null}"> <Setter TargetName="Icon" Property="Visibility" Value="Collapsed" /> </Trigger> <!-- 无标题时隐藏标题并移除图标边距 --> <Trigger Property="Header" Value="{x:Null}"> <Setter TargetName="Icon" Property="Margin" Value="0" /> <Setter TargetName="HeaderPresenter" Property="Visibility" Value="Collapsed" /> </Trigger> <!-- 鼠标悬停高亮效果 --> <Trigger Property="IsHighlighted" Value="True"> <Setter TargetName="Border" Property="Background" Value="{DynamicResource MaskColor}" /> </Trigger> <!-- 子菜单打开时的动画 --> <Trigger Property="IsSubmenuOpen" Value="True"> <Trigger.EnterActions> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetName="SubmenuBorder" Storyboard.TargetProperty="(Border.RenderTransform).(TranslateTransform.Y)" From="-45" To="0" Duration="{StaticResource MenuAnimationDuration}"> <DoubleAnimation.EasingFunction> <CircleEase EasingMode="EaseOut" /> </DoubleAnimation.EasingFunction> </DoubleAnimation> </Storyboard> </BeginStoryboard> </Trigger.EnterActions> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> <!-- 顶级菜单项模板(无子菜单) --> <ControlTemplate x:Key="{x:Static MenuItem.TopLevelItemTemplateKey}" TargetType="{x:Type MenuItem}"> <Border x:Name="Border" Margin="{StaticResource TopLevelItemMargin}" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="{StaticResource TopLevelCornerRadius}"> <Grid Margin="{StaticResource TopLevelContentMargin}"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <!-- 图标区域 --> <ContentPresenter x:Name="Icon" Grid.Column="0" Margin="0,0,6,0" VerticalAlignment="Center" Content="{TemplateBinding Icon}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" /> <!-- 标题区域 --> <ContentPresenter x:Name="HeaderPresenter" Grid.Column="1" Margin="{TemplateBinding Padding}" VerticalAlignment="Center" ContentSource="Header" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" TextElement.Foreground="{TemplateBinding Foreground}" /> </Grid> </Border> <ControlTemplate.Triggers> <!-- 鼠标悬停效果 --> <Trigger Property="IsHighlighted" Value="True"> <Setter TargetName="Border" Property="Background" Value="{DynamicResource MaskColor}" /> </Trigger> <Trigger Property="Icon" Value="{x:Null}"> <Setter TargetName="Icon" Property="Visibility" Value="Collapsed" /> </Trigger> <Trigger Property="Header" Value="{x:Null}"> <Setter TargetName="Icon" Property="Margin" Value="0" /> <Setter TargetName="HeaderPresenter" Property="Visibility" Value="Collapsed" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> <!-- 子菜单项模板(无子级) --> <ControlTemplate x:Key="{x:Static MenuItem.SubmenuItemTemplateKey}" TargetType="{x:Type MenuItem}"> <Border x:Name="Border" Margin="{StaticResource MenuItemMargin}" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="{StaticResource MenuCornerRadius}"> <Grid Margin="{StaticResource MenuItemContentPadding}"> <Grid.ColumnDefinitions> <!-- 图标/复选框列,使用共享大小组确保对齐 --> <ColumnDefinition Width="Auto" SharedSizeGroup="MenuItemIconCol" /> <!-- 标题内容列 --> <ColumnDefinition Width="*" /> <!-- 快捷键提示列,使用共享大小组确保对齐 --> <ColumnDefinition Width="Auto" SharedSizeGroup="MenuItemRightPartCol" /> </Grid.ColumnDefinitions> <!-- 复选框图标容器 --> <Border x:Name="CheckBoxIconBorder" Grid.Column="0" VerticalAlignment="Center" Visibility="Collapsed"> <Path x:Name="CheckBoxIcon" Width="10" Height="10" HorizontalAlignment="Left" VerticalAlignment="Center" Fill="{TemplateBinding Foreground}" Stretch="Uniform" /> </Border> <!-- 自定义图标 --> <ContentPresenter x:Name="Icon" Grid.Column="0" Margin="0,0,6,0" VerticalAlignment="Center" Content="{TemplateBinding Icon}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" /> <!-- 菜单项标题内容 --> <ContentPresenter Grid.Column="1" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" ContentSource="Header" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" TextElement.Foreground="{TemplateBinding Foreground}" /> <!-- 快捷键提示文本 --> <TextBlock x:Name="InputGestureText" Grid.Column="2" Margin="25,0,0,0" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" DockPanel.Dock="Right" FontSize="11" Opacity="0.67" Text="{TemplateBinding InputGestureText}" /> </Grid> </Border> <ControlTemplate.Triggers> <!-- 高亮状态(鼠标悬停) --> <Trigger Property="IsHighlighted" Value="True"> <Setter TargetName="Border" Property="Background" Value="{DynamicResource MaskColor}" /> </Trigger> <!-- 无自定义图标时隐藏图标区域 --> <Trigger Property="Icon" Value="{x:Null}"> <Setter TargetName="Icon" Property="Visibility" Value="Collapsed" /> </Trigger> <!-- 可复选时显示复选框图标容器 --> <Trigger Property="IsCheckable" Value="True"> <Setter TargetName="CheckBoxIconBorder" Property="Visibility" Value="Visible" /> </Trigger> <!-- 已选中时显示复选标记 --> <Trigger Property="IsChecked" Value="True"> <Setter TargetName="CheckBoxIcon" Property="Data" Value="{StaticResource CheckGraph}" /> </Trigger> <!-- 无快捷键时隐藏快捷键提示 --> <Trigger Property="InputGestureText" Value=""> <Setter TargetName="InputGestureText" Property="Visibility" Value="Collapsed" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> <!-- 子菜单头部模板(带下级子菜单) --> <ControlTemplate x:Key="{x:Static MenuItem.SubmenuHeaderTemplateKey}" TargetType="{x:Type MenuItem}"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <!-- 菜单项外观 --> <Border x:Name="Border" Grid.Row="1" Height="{TemplateBinding Height}" Margin="{StaticResource MenuItemMargin}" Background="Transparent" CornerRadius="{StaticResource MenuCornerRadius}"> <Grid x:Name="MenuItemContent" Margin="{StaticResource MenuItemContentPadding}"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" SharedSizeGroup="MenuItemIconCol" /> <ColumnDefinition Width="*" /> <ColumnDefinition Width="Auto" SharedSizeGroup="MenuItemRightPartCol" /> </Grid.ColumnDefinitions> <!-- 图标 --> <ContentPresenter x:Name="Icon" Grid.Column="0" Margin="0,0,6,0" VerticalAlignment="Center" Content="{TemplateBinding Icon}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" /> <!-- 标题 --> <ContentPresenter x:Name="HeaderHost" Grid.Column="1" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" ContentSource="Header" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" /> <!-- 右箭头指示器(表示有子菜单) --> <Path Grid.Column="2" Width="10" Height="10" Margin="0,0,4,0" HorizontalAlignment="Right" VerticalAlignment="Center" Data="{StaticResource ForwardGraph}" Fill="{TemplateBinding Foreground}" Opacity="0.67" Stretch="Uniform" /> </Grid> </Border> <!-- 子菜单弹出窗口(向右展开) --> <local:FluentPopup x:Name="PART_Popup" Grid.Row="1" Focusable="False" IsOpen="{TemplateBinding IsSubmenuOpen}" Placement="Right" PlacementTarget="{Binding ElementName=MenuItemContent}" PopupAnimation="None"> <Grid x:Name="PopupRoot" Background="{DynamicResource PopupWindowBackground}"> <!-- 子菜单动画变换 --> <Grid.RenderTransform> <TranslateTransform /> </Grid.RenderTransform> <ScrollViewer Padding="{StaticResource MenuBorderPadding}" CanContentScroll="True" Style="{StaticResource MenuItemScrollViewerStyle}"> <!-- 子菜单项容器 --> <ItemsPresenter x:Name="ItemsPresenter" Grid.IsSharedSizeScope="True" KeyboardNavigation.DirectionalNavigation="Cycle" KeyboardNavigation.TabNavigation="Cycle" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" /> </ScrollViewer> </Grid> </local:FluentPopup> </Grid> <ControlTemplate.Triggers> <!-- 无图标时优化布局 --> <Trigger Property="Icon" Value="{x:Null}"> <Setter TargetName="Icon" Property="Visibility" Value="Collapsed" /> <Setter TargetName="Icon" Property="Margin" Value="0" /> </Trigger> <!-- 高亮效果 --> <Trigger Property="IsHighlighted" Value="true"> <Setter TargetName="Border" Property="Background" Value="{DynamicResource MaskColor}" /> </Trigger> <!-- 子菜单打开动画 --> <Trigger Property="IsSubmenuOpen" Value="True"> <Trigger.EnterActions> <BeginStoryboard> <Storyboard> <!-- Y轴平移动画:从-45向下滑入到0 --> <DoubleAnimation Storyboard.TargetName="PopupRoot" Storyboard.TargetProperty="(Grid.RenderTransform).(TranslateTransform.Y)" From="-45" To="0" Duration="{StaticResource MenuAnimationDuration}"> <DoubleAnimation.EasingFunction> <CircleEase EasingMode="EaseOut" /> </DoubleAnimation.EasingFunction> </DoubleAnimation> </Storyboard> </BeginStoryboard> </Trigger.EnterActions> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> <!-- 默认菜单项样式 --> <Style x:Key="DefaultMenuItemStyle" TargetType="{x:Type MenuItem}"> <Setter Property="FocusVisualStyle" Value="{DynamicResource DefaultCollectionFocusVisualStyle}" /> <Setter Property="KeyboardNavigation.IsTabStop" Value="True" /> <Setter Property="Background" Value="Transparent" /> <Setter Property="BorderBrush" Value="Transparent" /> <Setter Property="BorderThickness" Value="1" /> <Setter Property="Focusable" Value="True" /> <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" /> <Setter Property="Height" Value="{x:Static sys:Double.NaN}" /> </Trigger> <!-- 顶级菜单项(无子菜单) --> <Trigger Property="Role" Value="TopLevelItem"> <Setter Property="Template" Value="{StaticResource {x:Static MenuItem.TopLevelItemTemplateKey}}" /> <Setter Property="Height" Value="{x:Static sys:Double.NaN}" /> </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> </ResourceDictionary>
三、应用模板和样式到全局

将上面的资源字典合并到应用程序资源中,然后为ContextMenuMenuItem指定默认样式:

<Style BasedOn="{StaticResource DefaultContextMenuStyle}" TargetType="{x:Type ContextMenu}"> <Style.Setters> <Setter Property="local:FluentTooltip.UseFluentStyle" Value="True" /> <Setter Property="Background" Value="{DynamicResource PopupWindowBackground}" /> <Setter Property="Foreground" Value="{DynamicResource ForeColor}" /> </Style.Setters> </Style> <Style BasedOn="{StaticResource DefaultMenuItemStyle}" TargetType="MenuItem"> <Setter Property="Height" Value="36" /> <Setter Property="Foreground" Value="{DynamicResource ForeColor}" /> <Setter Property="VerticalContentAlignment" Value="Center" /> </Style>

注意,ContextMenu需要使用之前文章中的FluentTooltip.UseFluentStyle来实现亚克力材质特效。其内部原理都是反射获取popuphwnd句柄,然后附加WindowMaterial特效。

参考连接

ContextMenu Styles and Templates WPF | Microsoft Learn[3]

Menu Styles and Templates WPF | Microsoft Learn[4]

PresentationFramework.Fluent/Themes/Fluent.xaml | GitHub[5]

参考资料

[1]

原文链接:https://www.cnblogs.com/TwilightLemon/p/19241723

[2]

Demo:https://github.com/TwilightLemon/WindowEffectTest

[3]

ContextMenu Styles and Templates WPF | Microsoft Learn:https://learn.microsoft.com/en-us/dotnet/desktop/wpf/controls/contextmenu-styles-and-templates

[4]

Menu Styles and Templates WPF | Microsoft Learn:https://learn.microsoft.com/en-us/dotnet/desktop/wpf/controls/menu-styles-and-templates

[5]

PresentationFramework.Fluent/Themes/Fluent.xaml | GitHub:https://github.com/dotnet/wpf/blob/main/src/Microsoft.DotNet.Wpf/src/Themes/PresentationFramework.Fluent/Themes/Fluent.xaml

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/16 4:33:36

终极指南:3步完成视觉Transformer架构重组实现精度突破

终极指南&#xff1a;3步完成视觉Transformer架构重组实现精度突破 【免费下载链接】vit-pytorch lucidrains/vit-pytorch: vit-pytorch是一个基于PyTorch实现的Vision Transformer (ViT)库&#xff0c;ViT是一种在计算机视觉领域广泛应用的Transformer模型&#xff0c;用于图像…

作者头像 李华
网站建设 2026/5/10 19:11:48

GPT2-Chinese长文本生成:3步突破1024上下文限制的终极方案

GPT2-Chinese长文本生成&#xff1a;3步突破1024上下文限制的终极方案 【免费下载链接】GPT2-Chinese Chinese version of GPT2 training code, using BERT tokenizer. 项目地址: https://gitcode.com/gh_mirrors/gp/GPT2-Chinese GPT2-Chinese作为专为中文优化的开源语…

作者头像 李华
网站建设 2026/5/1 0:14:37

彻底攻克FanControl风扇曲线异常:从故障诊断到系统级修复指南

你是否发现FanControl的风扇曲线设置突然失效&#xff1f;温度升高时风扇转速纹丝不动&#xff0c;或者出现异常跳变&#xff1f;这不仅仅是软件bug&#xff0c;更可能是复杂的系统级问题。作为你的技术顾问&#xff0c;我将带你深入排查&#xff0c;找出问题根源并提供完整的解…

作者头像 李华
网站建设 2026/5/7 19:11:01

Langchain-Chatchat项目git下载速度优化技巧

Langchain-Chatchat 项目 Git 下载速度优化实战指南 在部署本地大语言模型应用时&#xff0c;你是否曾经历过这样的场景&#xff1a;满怀期待地打开终端&#xff0c;输入 git clone https://github.com/chatchat-space/Langchain-Chatchat&#xff0c;然后眼睁睁看着下载速度卡…

作者头像 李华
网站建设 2026/5/9 7:19:39

5个必学的Blender贝塞尔曲线插件技巧:让你的建模效率翻倍

5个必学的Blender贝塞尔曲线插件技巧&#xff1a;让你的建模效率翻倍 【免费下载链接】blenderbezierutils 项目地址: https://gitcode.com/gh_mirrors/bl/blenderbezierutils Blender Bezier Utilities 是一款专为Blender设计的强大开源插件&#xff0c;提供了一系列高…

作者头像 李华