当前位置:   article > 正文

改进的WPF MenuItem模板_wpf menuitem 样式

wpf menuitem 样式

目录

为什么他们这么丑?

改进的外观

分析

解决方案

测试

结论


为什么他们这么丑?

为什么菜单项看起来这么难看?我看看。首先,让我们创建没有任何图标的菜单:

这就是大多数人抱怨的:左边有一个视觉上空的单元格。它被设计成一个图标,但没有一个图标,这一切看起来都令人不安,就像无头骑士一样。首先,人们要求删除这个区域并放弃图标。有很多解决方案,我发现它们不令人满意。更重要的是,为什么要放弃图标?至少可以选择拥有它们会更好,但要有适当的渲染。

如果父菜单项的弹出区域中的所有或大多数菜单项都具有图标,则看起来会更好:

够好吗?一点也不!要查看问题,让我们放大菜单字体:

现在,图标无法正确呈现。在这里,我使用字符作为图标,为了简单起见,以及其他一些很好的理由,它确实有效。请注意,使用非默认字体大小时,表示字形的字符与菜单标题的字符不一致。如果我使用大小正好为16x16的位图字形,它总是适合的,但看起来与文本不一致。使用不同的图像大小时,会出现一些其他渲染问题,但通常,渲染任何具有较大尺寸的内容都永远不会准确。毋庸置疑,尝试匹配每个所需字体的大小将是一个非常糟糕的主意。这不仅完全不可靠,而且意味着要扼杀维护。

WPF Menu处理由任意类型的数据表示的MenuItem类型的文本菜单项和图标。

改进的外观

不是更好吗?

上图显示了我的最终结果。我故意把字体做得很大,以显示所有细节。在讨论问题和解决方案之前,让我们先看一下。完美吗?不,不是。首先,我不得不牺牲图标和标题区域之间的垂直分隔符。可以接受吗?由您决定。我想说,这种外观并不完全好,但仍然比没有修复要好。

对于那些选择不使用那些水平菜单分隔符的人来说,没有垂直分隔符从各方面来看都更好。此外,不同菜单项的图标以同一条垂直线为中心。

我测试了许多字体大小,甚至走到极端,以及不同的内容——一切正常。

现在,让我们讨论解决方案。

分析

当我查看Microsoft的默认WPF MenuItem模板时,我发现许多硬编码值会影响项目的大小和布局。很明显,该Menu控件被设计为与默认的固定字体和只有一个固定大小(16x16)的图标一起使用。换句话说,从我的角度来看,这是一个典型的临时布局示例——一个很大的设计错误。

但是,结构有点太复杂了,很容易被打破。我试图尽可能保守地修改它。首先,我发现在几个地方发现的16号是多余的,可以去掉。我还发现物品的高度是有限制的,限制等于22。我决定不删除它,而只是从Grid行大小中删除它。

最困难的问题是图标和标题区域之间的垂直分隔符。我决定放弃它并删除它,因为它的正确放置需要对一切进行彻底的重组。在默认的XAML代码中,三个Grid元素在同一个Grid.Raw中重叠,因此表示分隔符的Rectangle布局由硬编码Margins属性定义。我知道这是一个技巧,用于对齐几个堆叠菜单项的所有分隔符,但这是一种不好的做法。请注意,其他WPF控件(ListViewDataGrid)没有此问题。

解决方案

此代码可用作单独的ResourceDictionary文件:

  1. <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  2. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  3. <SolidColorBrush x:Key="Menu.Static.Background" Color="#FFF0F0F0"/>
  4. <SolidColorBrush x:Key="Menu.Static.Border" Color="#FF999999"/>
  5. <SolidColorBrush x:Key="Menu.Static.Foreground" Color="#FF212121"/>
  6. <!-- SA!!! removed because it is unused: the element using it cannot be positioned correctly as menu font size increases
  7. <SolidColorBrush x:Key="Menu.Static.Separator" Color="#FFD7D7D7"/>
  8. -->
  9. <SolidColorBrush x:Key="Menu.Disabled.Foreground" Color="#FF707070"/>
  10. <SolidColorBrush x:Key="MenuItem.Selected.Background" Color="#3D26A0DA"/>
  11. <SolidColorBrush x:Key="MenuItem.Selected.Border" Color="#FF26A0DA"/>
  12. <SolidColorBrush x:Key="MenuItem.Highlight.Background" Color="#3D26A0DA"/>
  13. <SolidColorBrush x:Key="MenuItem.Highlight.Border" Color="#FF26A0DA"/>
  14. <SolidColorBrush x:Key="MenuItem.Highlight.Disabled.Background" Color="#0A000000"/>
  15. <SolidColorBrush x:Key="MenuItem.Highlight.Disabled.Border" Color="#21000000"/>
  16. <MenuScrollingVisibilityConverter x:Key="MenuScrollingVisibilityConverter"/>
  17. <Geometry x:Key="DownArrow">M 0,0 L 3.5,4 L 7,0 Z</Geometry>
  18. <Geometry x:Key="UpArrow">M 0,4 L 3.5,0 L 7,4 Z</Geometry>
  19. <Geometry x:Key="RightArrow">M 0,0 L 4,3.5 L 0,7 Z</Geometry>
  20. <Geometry x:Key="Checkmark">F1 M 10.0,1.2 L 4.7,9.1 L 4.5,9.1 L 0,5.2 L 1.3,3.5 L 4.3,6.1L 8.3,0 L 10.0,1.2 Z</Geometry>
  21. <Style x:Key="MenuScrollButton" BasedOn="{x:Null}" TargetType="{x:Type RepeatButton}">
  22. <Setter Property="ClickMode" Value="Hover"/>
  23. <Setter Property="Template">
  24. <Setter.Value>
  25. <ControlTemplate TargetType="{x:Type RepeatButton}">
  26. <Border x:Name="templateRoot" Background="Transparent" BorderBrush="Transparent" BorderThickness="1" SnapsToDevicePixels="true">
  27. <ContentPresenter HorizontalAlignment="Center" Margin="6" VerticalAlignment="Center"/>
  28. </Border>
  29. </ControlTemplate>
  30. </Setter.Value>
  31. </Setter>
  32. </Style>
  33. <Style x:Key="{ComponentResourceKey ResourceId=MenuScrollViewer, TypeInTargetAssembly={x:Type FrameworkElement}}" BasedOn="{x:Null}" TargetType="{x:Type ScrollViewer}">
  34. <Setter Property="HorizontalScrollBarVisibility" Value="Hidden"/>
  35. <Setter Property="VerticalScrollBarVisibility" Value="Auto"/>
  36. <Setter Property="Template">
  37. <Setter.Value>
  38. <ControlTemplate TargetType="{x:Type ScrollViewer}">
  39. <Grid SnapsToDevicePixels="true">
  40. <Grid.ColumnDefinitions>
  41. <ColumnDefinition Width="*"/>
  42. </Grid.ColumnDefinitions>
  43. <Grid.RowDefinitions>
  44. <RowDefinition Height="Auto"/>
  45. <RowDefinition Height="*"/>
  46. <RowDefinition Height="Auto"/>
  47. </Grid.RowDefinitions>
  48. <Border Grid.Column="0" Grid.Row="1">
  49. <ScrollContentPresenter CanContentScroll="{TemplateBinding CanContentScroll}" Margin="{TemplateBinding Padding}"/>
  50. </Border>
  51. <RepeatButton Command="{x:Static ScrollBar.LineUpCommand}" CommandTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}" Grid.Column="0" Focusable="false" Grid.Row="0" Style="{StaticResource MenuScrollButton}">
  52. <RepeatButton.Visibility>
  53. <MultiBinding ConverterParameter="0" Converter="{StaticResource MenuScrollingVisibilityConverter}" FallbackValue="Visibility.Collapsed">
  54. <Binding Path="ComputedVerticalScrollBarVisibility" RelativeSource="{RelativeSource TemplatedParent}"/>
  55. <Binding Path="VerticalOffset" RelativeSource="{RelativeSource TemplatedParent}"/>
  56. <Binding Path="ExtentHeight" RelativeSource="{RelativeSource TemplatedParent}"/>
  57. <Binding Path="ViewportHeight" RelativeSource="{RelativeSource TemplatedParent}"/>
  58. </MultiBinding>
  59. </RepeatButton.Visibility>
  60. <Path Data="{StaticResource UpArrow}" Fill="{StaticResource Menu.Static.Foreground}"/>
  61. </RepeatButton>
  62. <RepeatButton Command="{x:Static ScrollBar.LineDownCommand}" CommandTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}" Grid.Column="0" Focusable="false" Grid.Row="2" Style="{StaticResource MenuScrollButton}">
  63. <RepeatButton.Visibility>
  64. <MultiBinding ConverterParameter="100" Converter="{StaticResource MenuScrollingVisibilityConverter}" FallbackValue="Visibility.Collapsed">
  65. <Binding Path="ComputedVerticalScrollBarVisibility" RelativeSource="{RelativeSource TemplatedParent}"/>
  66. <Binding Path="VerticalOffset" RelativeSource="{RelativeSource TemplatedParent}"/>
  67. <Binding Path="ExtentHeight" RelativeSource="{RelativeSource TemplatedParent}"/>
  68. <Binding Path="ViewportHeight" RelativeSource="{RelativeSource TemplatedParent}"/>
  69. </MultiBinding>
  70. </RepeatButton.Visibility>
  71. <Path Data="{StaticResource DownArrow}" Fill="{StaticResource Menu.Static.Foreground}"/>
  72. </RepeatButton>
  73. </Grid>
  74. </ControlTemplate>
  75. </Setter.Value>
  76. </Setter>
  77. </Style>
  78. <ControlTemplate x:Key="{ComponentResourceKey ResourceId=TopLevelItemTemplateKey, TypeInTargetAssembly={x:Type MenuItem}}" TargetType="{x:Type MenuItem}">
  79. <Border x:Name="templateRoot" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="true">
  80. <Grid VerticalAlignment="Center">
  81. <Grid.ColumnDefinitions>
  82. <ColumnDefinition Width="Auto"/>
  83. <ColumnDefinition Width="Auto"/>
  84. </Grid.ColumnDefinitions>
  85. <ContentPresenter x:Name="Icon" ContentSource="Icon" HorizontalAlignment="Center" Margin="3" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center" />
  86. <Path x:Name="GlyphPanel" Data="{StaticResource Checkmark}" FlowDirection="LeftToRight" Fill="{StaticResource Menu.Static.Foreground}" Margin="3" VerticalAlignment="Center" Visibility="Collapsed"/>
  87. <ContentPresenter ContentSource="Header" Grid.Column="1" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
  88. </Grid>
  89. </Border>
  90. <ControlTemplate.Triggers>
  91. <Trigger Property="Icon" Value="{x:Null}">
  92. <Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
  93. </Trigger>
  94. <Trigger Property="IsChecked" Value="true">
  95. <Setter Property="Visibility" TargetName="GlyphPanel" Value="Visible"/>
  96. <Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
  97. </Trigger>
  98. <Trigger Property="IsHighlighted" Value="True">
  99. <Setter Property="Background" TargetName="templateRoot" Value="{StaticResource MenuItem.Highlight.Background}"/>
  100. <Setter Property="BorderBrush" TargetName="templateRoot" Value="{StaticResource MenuItem.Highlight.Border}"/>
  101. </Trigger>
  102. <Trigger Property="IsEnabled" Value="False">
  103. <Setter Property="TextElement.Foreground" TargetName="templateRoot" Value="{StaticResource Menu.Disabled.Foreground}"/>
  104. <Setter Property="Fill" TargetName="GlyphPanel" Value="{StaticResource Menu.Disabled.Foreground}"/>
  105. </Trigger>
  106. <MultiTrigger>
  107. <MultiTrigger.Conditions>
  108. <Condition Property="IsHighlighted" Value="True"/>
  109. <Condition Property="IsEnabled" Value="False"/>
  110. </MultiTrigger.Conditions>
  111. <Setter Property="Background" TargetName="templateRoot" Value="{StaticResource MenuItem.Highlight.Disabled.Background}"/>
  112. <Setter Property="BorderBrush" TargetName="templateRoot" Value="{StaticResource MenuItem.Highlight.Disabled.Border}"/>
  113. </MultiTrigger>
  114. </ControlTemplate.Triggers>
  115. </ControlTemplate>
  116. <ControlTemplate x:Key="{ComponentResourceKey ResourceId=TopLevelHeaderTemplateKey, TypeInTargetAssembly={x:Type MenuItem}}" TargetType="{x:Type MenuItem}">
  117. <Border x:Name="templateRoot" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="true">
  118. <Grid VerticalAlignment="Center">
  119. <Grid.ColumnDefinitions>
  120. <ColumnDefinition Width="Auto"/>
  121. <ColumnDefinition Width="Auto"/>
  122. </Grid.ColumnDefinitions>
  123. <ContentPresenter x:Name="Icon" ContentSource="Icon" HorizontalAlignment="Center" Margin="3" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center" />
  124. <Path x:Name="GlyphPanel" Data="{StaticResource Checkmark}" FlowDirection="LeftToRight" Fill="{TemplateBinding Foreground}" Margin="3" VerticalAlignment="Center" Visibility="Collapsed"/>
  125. <ContentPresenter ContentSource="Header" Grid.Column="1" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
  126. <Popup x:Name="PART_Popup" AllowsTransparency="true" Focusable="false" IsOpen="{Binding IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}" Placement="Bottom" PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}" PlacementTarget="{Binding ElementName=templateRoot}">
  127. <Border x:Name="SubMenuBorder" Background="{StaticResource Menu.Static.Background}" BorderBrush="{StaticResource Menu.Static.Border}" BorderThickness="1" Padding="2">
  128. <ScrollViewer x:Name="SubMenuScrollViewer" Style="{DynamicResource {ComponentResourceKey ResourceId=MenuScrollViewer, TypeInTargetAssembly={x:Type FrameworkElement}}}">
  129. <Grid RenderOptions.ClearTypeHint="Enabled">
  130. <Canvas HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
  131. <Rectangle x:Name="OpaqueRect" Fill="{Binding Background, ElementName=SubMenuBorder}" Height="{Binding ActualHeight, ElementName=SubMenuBorder}" Width="{Binding ActualWidth, ElementName=SubMenuBorder}"/>
  132. </Canvas>
  133. <!-- SA!!! removed because it cannot be positioned correctly as menu font size increases
  134. <Rectangle Fill="{StaticResource Menu.Static.Separator}" HorizontalAlignment="Left" Margin="29,2,0,2" Width="1"/>
  135. -->
  136. <ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Cycle" Grid.IsSharedSizeScope="true" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" KeyboardNavigation.TabNavigation="Cycle"/>
  137. </Grid>
  138. </ScrollViewer>
  139. </Border>
  140. </Popup>
  141. </Grid>
  142. </Border>
  143. <ControlTemplate.Triggers>
  144. <Trigger Property="IsSuspendingPopupAnimation" Value="true">
  145. <Setter Property="PopupAnimation" TargetName="PART_Popup" Value="None"/>
  146. </Trigger>
  147. <Trigger Property="Icon" Value="{x:Null}">
  148. <Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
  149. </Trigger>
  150. <Trigger Property="IsChecked" Value="true">
  151. <Setter Property="Visibility" TargetName="GlyphPanel" Value="Visible"/>
  152. <Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
  153. </Trigger>
  154. <Trigger Property="IsHighlighted" Value="True">
  155. <Setter Property="Background" TargetName="templateRoot" Value="{StaticResource MenuItem.Highlight.Background}"/>
  156. <Setter Property="BorderBrush" TargetName="templateRoot" Value="{StaticResource MenuItem.Highlight.Border}"/>
  157. </Trigger>
  158. <Trigger Property="IsEnabled" Value="False">
  159. <Setter Property="TextElement.Foreground" TargetName="templateRoot" Value="{StaticResource Menu.Disabled.Foreground}"/>
  160. <Setter Property="Fill" TargetName="GlyphPanel" Value="{StaticResource Menu.Disabled.Foreground}"/>
  161. </Trigger>
  162. <Trigger Property="ScrollViewer.CanContentScroll" SourceName="SubMenuScrollViewer" Value="false">
  163. <Setter Property="Canvas.Top" TargetName="OpaqueRect" Value="{Binding VerticalOffset, ElementName=SubMenuScrollViewer}"/>
  164. <Setter Property="Canvas.Left" TargetName="OpaqueRect" Value="{Binding HorizontalOffset, ElementName=SubMenuScrollViewer}"/>
  165. </Trigger>
  166. </ControlTemplate.Triggers>
  167. </ControlTemplate>
  168. <ControlTemplate x:Key="{ComponentResourceKey ResourceId=SubmenuItemTemplateKey, TypeInTargetAssembly={x:Type MenuItem}}" TargetType="{x:Type MenuItem}">
  169. <Border x:Name="templateRoot" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="true">
  170. <Grid Margin="-1">
  171. <Grid.ColumnDefinitions>
  172. <ColumnDefinition MinWidth="22" SharedSizeGroup="MenuItemIconColumnGroup" Width="Auto"/>
  173. <ColumnDefinition Width="13"/>
  174. <ColumnDefinition Width="*"/>
  175. <ColumnDefinition Width="30"/>
  176. <ColumnDefinition SharedSizeGroup="MenuItemIGTColumnGroup" Width="Auto"/>
  177. <ColumnDefinition Width="20"/>
  178. </Grid.ColumnDefinitions>
  179. <ContentPresenter x:Name="Icon" ContentSource="Icon" HorizontalAlignment="Center" Margin="3" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center" />
  180. <Border x:Name="GlyphPanel" Background="{StaticResource MenuItem.Selected.Background}" BorderBrush="{StaticResource MenuItem.Selected.Border}" BorderThickness="1" ClipToBounds="False" HorizontalAlignment="Center" Height="22" Margin="-1,0,0,0" VerticalAlignment="Center" Visibility="Hidden" Width="22">
  181. <Path x:Name="Glyph" Data="{StaticResource Checkmark}" FlowDirection="LeftToRight" Fill="{StaticResource Menu.Static.Foreground}" Height="11" Width="10"/>
  182. </Border>
  183. <ContentPresenter x:Name="menuHeaderContainer" ContentSource="Header" Grid.Column="2" HorizontalAlignment="Left" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center"/>
  184. <TextBlock x:Name="menuGestureText" Grid.Column="4" Margin="{TemplateBinding Padding}" Opacity="0.7" Text="{TemplateBinding InputGestureText}" VerticalAlignment="Center"/>
  185. </Grid>
  186. </Border>
  187. <ControlTemplate.Triggers>
  188. <Trigger Property="Icon" Value="{x:Null}">
  189. <Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
  190. </Trigger>
  191. <Trigger Property="IsChecked" Value="True">
  192. <Setter Property="Visibility" TargetName="GlyphPanel" Value="Visible"/>
  193. <Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
  194. </Trigger>
  195. <Trigger Property="IsHighlighted" Value="True">
  196. <Setter Property="Background" TargetName="templateRoot" Value="{StaticResource MenuItem.Highlight.Background}"/>
  197. <Setter Property="BorderBrush" TargetName="templateRoot" Value="{StaticResource MenuItem.Highlight.Border}"/>
  198. </Trigger>
  199. <Trigger Property="IsEnabled" Value="False">
  200. <Setter Property="TextElement.Foreground" TargetName="templateRoot" Value="{StaticResource Menu.Disabled.Foreground}"/>
  201. <Setter Property="Fill" TargetName="Glyph" Value="{StaticResource Menu.Disabled.Foreground}"/>
  202. </Trigger>
  203. <MultiTrigger>
  204. <MultiTrigger.Conditions>
  205. <Condition Property="IsHighlighted" Value="True"/>
  206. <Condition Property="IsEnabled" Value="False"/>
  207. </MultiTrigger.Conditions>
  208. <Setter Property="Background" TargetName="templateRoot" Value="{StaticResource MenuItem.Highlight.Disabled.Background}"/>
  209. <Setter Property="BorderBrush" TargetName="templateRoot" Value="{StaticResource MenuItem.Highlight.Disabled.Border}"/>
  210. </MultiTrigger>
  211. </ControlTemplate.Triggers>
  212. </ControlTemplate>
  213. <ControlTemplate x:Key="{ComponentResourceKey ResourceId=SubmenuHeaderTemplateKey, TypeInTargetAssembly={x:Type MenuItem}}" TargetType="{x:Type MenuItem}">
  214. <Border x:Name="templateRoot" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="true">
  215. <Grid Margin="-1">
  216. <Grid.ColumnDefinitions>
  217. <ColumnDefinition MinWidth="22" SharedSizeGroup="MenuItemIconColumnGroup" Width="Auto"/>
  218. <ColumnDefinition Width="13"/>
  219. <ColumnDefinition Width="*"/>
  220. <ColumnDefinition Width="30"/>
  221. <ColumnDefinition SharedSizeGroup="MenuItemIGTColumnGroup" Width="Auto"/>
  222. <ColumnDefinition Width="20"/>
  223. </Grid.ColumnDefinitions>
  224. <ContentPresenter x:Name="Icon" ContentSource="Icon" HorizontalAlignment="Center" Margin="3" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center" />
  225. <Border x:Name="GlyphPanel" Background="{StaticResource MenuItem.Highlight.Background}" BorderBrush="{StaticResource MenuItem.Highlight.Border}" BorderThickness="1" Height="22" Margin="-1,0,0,0" VerticalAlignment="Center" Visibility="Hidden" Width="22">
  226. <Path x:Name="Glyph" Data="{DynamicResource Checkmark}" FlowDirection="LeftToRight" Fill="{StaticResource Menu.Static.Foreground}" Height="11" Width="9"/>
  227. </Border>
  228. <ContentPresenter ContentSource="Header" Grid.Column="2" HorizontalAlignment="Left" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center"/>
  229. <TextBlock Grid.Column="4" Margin="{TemplateBinding Padding}" Opacity="0.7" Text="{TemplateBinding InputGestureText}" VerticalAlignment="Center"/>
  230. <Path x:Name="RightArrow" Grid.Column="5" Data="{StaticResource RightArrow}" Fill="{StaticResource Menu.Static.Foreground}" HorizontalAlignment="Left" Margin="10,0,0,0" VerticalAlignment="Center"/>
  231. <Popup x:Name="PART_Popup" AllowsTransparency="true" Focusable="false" HorizontalOffset="-2" IsOpen="{Binding IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}" Placement="Right" PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}" VerticalOffset="-3">
  232. <Border x:Name="SubMenuBorder" Background="{StaticResource Menu.Static.Background}" BorderBrush="{StaticResource Menu.Static.Border}" BorderThickness="1" Padding="2">
  233. <ScrollViewer x:Name="SubMenuScrollViewer" Style="{DynamicResource {ComponentResourceKey ResourceId=MenuScrollViewer, TypeInTargetAssembly={x:Type FrameworkElement}}}">
  234. <Grid RenderOptions.ClearTypeHint="Enabled">
  235. <Canvas HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
  236. <Rectangle x:Name="OpaqueRect" Fill="{Binding Background, ElementName=SubMenuBorder}" Height="{Binding ActualHeight, ElementName=SubMenuBorder}" Width="{Binding ActualWidth, ElementName=SubMenuBorder}"/>
  237. </Canvas>
  238. <Rectangle Fill="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}" HorizontalAlignment="Left" Margin="29,2,0,2" Width="1"/>
  239. <ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Cycle" Grid.IsSharedSizeScope="true" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" KeyboardNavigation.TabNavigation="Cycle"/>
  240. </Grid>
  241. </ScrollViewer>
  242. </Border>
  243. </Popup>
  244. </Grid>
  245. </Border>
  246. <ControlTemplate.Triggers>
  247. <Trigger Property="IsSuspendingPopupAnimation" Value="true">
  248. <Setter Property="PopupAnimation" TargetName="PART_Popup" Value="None"/>
  249. </Trigger>
  250. <Trigger Property="Icon" Value="{x:Null}">
  251. <Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
  252. </Trigger>
  253. <Trigger Property="IsChecked" Value="True">
  254. <Setter Property="Visibility" TargetName="GlyphPanel" Value="Visible"/>
  255. <Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
  256. </Trigger>
  257. <Trigger Property="IsHighlighted" Value="True">
  258. <Setter Property="Background" TargetName="templateRoot" Value="Transparent"/>
  259. <Setter Property="BorderBrush" TargetName="templateRoot" Value="{StaticResource MenuItem.Highlight.Border}"/>
  260. </Trigger>
  261. <Trigger Property="IsEnabled" Value="False">
  262. <Setter Property="TextElement.Foreground" TargetName="templateRoot" Value="{StaticResource Menu.Disabled.Foreground}"/>
  263. <Setter Property="Fill" TargetName="Glyph" Value="{StaticResource Menu.Disabled.Foreground}"/>
  264. <Setter Property="Fill" TargetName="RightArrow" Value="{StaticResource Menu.Disabled.Foreground}"/>
  265. </Trigger>
  266. <Trigger Property="ScrollViewer.CanContentScroll" SourceName="SubMenuScrollViewer" Value="false">
  267. <Setter Property="Canvas.Top" TargetName="OpaqueRect" Value="{Binding VerticalOffset, ElementName=SubMenuScrollViewer}"/>
  268. <Setter Property="Canvas.Left" TargetName="OpaqueRect" Value="{Binding HorizontalOffset, ElementName=SubMenuScrollViewer}"/>
  269. </Trigger>
  270. </ControlTemplate.Triggers>
  271. </ControlTemplate>
  272. <Style x:Key="MenuItemStyle1" TargetType="{x:Type MenuItem}">
  273. <Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
  274. <Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
  275. <Setter Property="Background" Value="Transparent"/>
  276. <Setter Property="BorderBrush" Value="Transparent"/>
  277. <Setter Property="BorderThickness" Value="1"/>
  278. <Setter Property="ScrollViewer.PanningMode" Value="Both"/>
  279. <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
  280. <Setter Property="Template" Value="{DynamicResource {ComponentResourceKey ResourceId=SubmenuItemTemplateKey, TypeInTargetAssembly={x:Type MenuItem}}}"/>
  281. <Style.Triggers>
  282. <Trigger Property="Role" Value="TopLevelHeader">
  283. <Setter Property="Background" Value="Transparent"/>
  284. <Setter Property="BorderBrush" Value="Transparent"/>
  285. <Setter Property="Foreground" Value="{StaticResource Menu.Static.Foreground}"/>
  286. <Setter Property="Template" Value="{DynamicResource {ComponentResourceKey ResourceId=TopLevelHeaderTemplateKey, TypeInTargetAssembly={x:Type MenuItem}}}"/>
  287. <Setter Property="Padding" Value="6,0"/>
  288. </Trigger>
  289. <Trigger Property="Role" Value="TopLevelItem">
  290. <Setter Property="Background" Value="{StaticResource Menu.Static.Background}"/>
  291. <Setter Property="BorderBrush" Value="{StaticResource Menu.Static.Border}"/>
  292. <Setter Property="Foreground" Value="{StaticResource Menu.Static.Foreground}"/>
  293. <Setter Property="Template" Value="{DynamicResource {ComponentResourceKey ResourceId=TopLevelItemTemplateKey, TypeInTargetAssembly={x:Type MenuItem}}}"/>
  294. <Setter Property="Padding" Value="6,0"/>
  295. </Trigger>
  296. <Trigger Property="Role" Value="SubmenuHeader">
  297. <Setter Property="Template" Value="{DynamicResource {ComponentResourceKey ResourceId=SubmenuHeaderTemplateKey, TypeInTargetAssembly={x:Type MenuItem}}}"/>
  298. </Trigger>
  299. </Style.Triggers>
  300. </Style>
  301. </ResourceDictionary>

无需引用在此资源字典中创建的样式。使用菜单将其包含在XAML中就足够了。然后,此资源字典将影响应用程序的所有项目。

请注意,可以使用以下ResourceDictionary.MergedDictionaries将资源字典包含在XAML中,请参阅文档文章合并的资源字典(WPF .NET)。

源资源字典不仅可以作为文件合并到XAML中,还可以作为资源或单独生成的程序集,使用对引用的程序集项目的程序集资源的引用。这可以通过使用包URI方案来实现,请参阅文档文章 WPF中的包URI

测试

此解决方案在具有不同内容和字体大小的.NET 5.NET 7上进行了测试。

结论

该解决方案确实有效。但是,它的目标是最小的修复,而没有尝试引入从根本上改进的结构。我对其进行了彻底的测试,该解决方案提供了比MenuItem默认模板更好的结果。

https://www.codeproject.com/Tips/5367587/Improved-WPF-MenuItem-Template

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号