如何在 WPF 中创建具有 Microsoft Web 应用程序样式的菜单
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/47561763/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to create a menu in WPF that has Microsoft Web Application styling
提问by Robert Harvey
We have been tasked with designing an enterprise application in WPF that will replace a battleship grey Winforms application with a modern look and feel.
我们的任务是在 WPF 中设计一个企业应用程序,它将用现代的外观和感觉取代战舰灰色的 Winforms 应用程序。
We like the look and feel that Microsoft web applications currently possess:
我们喜欢 Microsoft Web 应用程序当前拥有的外观和感觉:
We could create these menus in WPF in the usual way:
我们可以用通常的方式在 WPF 中创建这些菜单:
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem Header="_New" />
<MenuItem Header="_Open" />
<MenuItem Header="_Save" />
<Separator />
<MenuItem Header="_Exit" />
</MenuItem>
</Menu>
<TextBox AcceptsReturn="True" />
</DockPanel>
But we'd get something that looks like a Winforms menu.
但是我们会得到一些看起来像 Winforms 菜单的东西。
I've seen some rather impressive styling efforts like this one, but they all seem to have the same familiar Winforms shape. I've also seen menus in libraries like MahApps Metro, but these strike us as too spartan.
我见过一些类似这样的令人印象深刻的样式设计,但它们似乎都具有相同的熟悉的 Winforms 形状。我也看过像 MahApps Metro 这样的图书馆的菜单,但这些菜单让我们觉得太简陋了。
Is the WPF Menu control flexible enough to be styled as shown in the picture above, or should we go another route like building a custom menu control from Stack Panels and Lists? What are the tradeoffs?
WPF 菜单控件是否足够灵活以设置如上图所示的样式,还是我们应该走另一条路线,例如从堆栈面板和列表构建自定义菜单控件?有哪些权衡?
Bonus points (i.e. a bounty) will be awarded for xaml/code that does exactly this.
执行此操作的 xaml/代码将获得奖励积分(即赏金)。
An example of this menu style in action:
https://www.visualstudio.com/
此菜单样式的示例:https :
//www.visualstudio.com/
回答by Simon Mourier
WPF was really designed with the possibility to change the look and behavior of every out-of-the-box mechanisms / controls (buttons, menus, treeview, etc.). So, in general, it's better to do this rather than to rewrite everything. For example, if you redesign your custom menu, you'll have to think about keyboard, UI automation, etc...
WPF 的真正设计是可以更改每个开箱即用的机制/控件(按钮、菜单、树视图等)的外观和行为。因此,总的来说,最好这样做而不是重写所有内容。例如,如果您重新设计自定义菜单,则必须考虑键盘、UI 自动化等...
So, I gave a shot at your example and tried to build a minimum working sample - pure XAML - that mimics VS online menu (I've also added the hover background color change that's not by default in WPF's menu).
因此,我尝试了您的示例,并尝试构建一个最小的工作示例 - 纯 XAML - 模仿 VS 在线菜单(我还添加了 WPF 菜单中不默认的悬停背景颜色更改)。
Here is the result and, as you see, it looks very similar:
这是结果,如您所见,它看起来非常相似:
Here is the XAML. I've chosen to use a custom control template per each MenuItem. I think it's quite practical when you need to really customize every item.
这是 XAML。我选择为每个 MenuItem 使用自定义控件模板。我认为当您需要真正自定义每个项目时,它非常实用。
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="550" Width="525">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="btv" />
<!-- style a top level menu item -->
<ControlTemplate x:Key="VsMenuTop" TargetType="MenuItem">
<StackPanel TextBlock.FontSize="15px" Height="40">
<!-- label, icons, etc. -->
<Label Content="{TemplateBinding Header}" Margin="5" Foreground="White" />
<!-- sub items -->
<Popup IsOpen="{TemplateBinding IsSubmenuOpen}" AllowsTransparency="True" Focusable="False">
<Border BorderThickness="1" Background="White" BorderBrush="#E0E0E0">
<StackPanel IsItemsHost="True" />
</Border>
</Popup>
<StackPanel.Style>
<Style TargetType="StackPanel">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#106EBE" />
</Trigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
</StackPanel>
</ControlTemplate>
<!-- style a non-top level menu item -->
<ControlTemplate x:Key="VsMenuSub" TargetType="MenuItem">
<DockPanel TextBlock.FontSize="15px" x:Name="panel">
<!-- label, icons, etc. -->
<Image Source="{Binding Icon, RelativeSource={RelativeSource TemplatedParent}}" Width="20" Margin="5,0" />
<Label Content="{TemplateBinding Header}" Foreground="Black" Margin="0,5,5,5" />
<!-- draw the right arrow only if this menu item has sub items -->
<Image Source="icon_right.png" Visibility="{Binding HasItems, Converter={StaticResource btv}, RelativeSource={RelativeSource TemplatedParent}}" />
<!-- sub items -->
<Popup IsOpen="{TemplateBinding IsSubmenuOpen}" AllowsTransparency="True" Focusable="False" Placement="Right" >
<Border BorderThickness="1" Background="White" BorderBrush="#E0E0E0">
<StackPanel IsItemsHost="True" />
</Border>
</Popup>
</DockPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsHighlighted" Value="True">
<Setter Property="Background" TargetName="panel" Value="#EFF6FC" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!-- style the separator -->
<ControlTemplate x:Key="VsMenuSep" TargetType="Separator">
<Border Height="1" Background="#E0E0E0" />
</ControlTemplate>
<!-- style the VSOnline -->
<ControlTemplate x:Key="VsOnline" TargetType="MenuItem">
<StackPanel TextBlock.FontSize="15px" Height="40" Orientation="Horizontal" Background="#005A9E">
<Label Content="{TemplateBinding Header}" Margin="5" Foreground="White" />
<Image Source="icon_down.png" Height="20" Margin="0,0,5,0" />
<!-- sub items -->
<Popup IsOpen="{TemplateBinding IsSubmenuOpen}" AllowsTransparency="True" Focusable="False">
<Border BorderThickness="1" Background="White" BorderBrush="#E0E0E0">
<StackPanel IsItemsHost="True" />
</Border>
</Popup>
</StackPanel>
</ControlTemplate>
<!-- some base stuff -->
<Style TargetType="Menu">
<Setter Property="Background" Value="#0078D7" />
<Setter Property="Height" Value="40px" />
</Style>
</Window.Resources>
<!-- the real app and real menu -->
<StackPanel>
<Menu IsMainMenu="True">
<MenuItem Header="_VSOnline" Template="{StaticResource VsOnline}" >
<MenuItem Header="_Whatever" Template="{StaticResource VsMenuSub}" />
</MenuItem>
<MenuItem Header="_Dashboards" Template="{StaticResource VsMenuTop}">
<MenuItem Header="_Overview" Template="{StaticResource VsMenuSub}" />
</MenuItem>
<MenuItem Header="_Code" Template="{StaticResource VsMenuTop}">
<MenuItem Header="_Files" Template="{StaticResource VsMenuSub}" />
<MenuItem Header="_Commits" Template="{StaticResource VsMenuSub}" />
<MenuItem Header="_Pushes" Template="{StaticResource VsMenuSub}" />
</MenuItem>
<MenuItem Header="_Work" Template="{StaticResource VsMenuTop}">
<MenuItem Header="_Backlogs" Template="{StaticResource VsMenuSub}" Icon="icon_backlogs.png" />
<MenuItem Header="_Queries" Template="{StaticResource VsMenuSub}" Icon="icon_queries.png" />
<Separator Template="{StaticResource VsMenuSep}" />
<MenuItem Header="_New Work Item" Template="{StaticResource VsMenuSub}">
<MenuItem Header="_Epic" Template="{StaticResource VsMenuSub}" Icon="icon_epic.png" />
<MenuItem Header="_Feature" Template="{StaticResource VsMenuSub}" Icon="icon_feature.png" />
<MenuItem Header="_Issue" Template="{StaticResource VsMenuSub}" Icon="icon_issue.png" />
<MenuItem Header="_Task" Template="{StaticResource VsMenuSub}" Icon="icon_task.png" />
<MenuItem Header="_Test Case" Template="{StaticResource VsMenuSub}" Icon="icon_testcase.png" />
<MenuItem Header="_User Story" Template="{StaticResource VsMenuSub}" Icon="icon_userstory.png" />
</MenuItem>
<MenuItem Header="_Bug" Template="{StaticResource VsMenuSub}" Icon="icon_bug.png" />
</MenuItem>
</Menu>
</StackPanel>
</Window>
The project is available here on github.
该项目可在 github 上获得。
回答by Arek Bal
You are probably looking for some Wpf Theme to start with.
您可能正在寻找一些 Wpf 主题作为开始。
Such as http://brianlagunas.com/free-metro-light-and-dark-themes-for-wpf-and-silverlight-microsoft-controls/or have a look at that SO answer: Any free WPF themes?
例如 http://brianlagunas.com/free-metro-light-and-dark-themes-for-wpf-and-silverlight-microsoft-controls/或者看看那个 SO 答案: 任何免费的 WPF 主题?
Then you probably would want to customize it even more with look and feelyou are looking for.
然后,您可能希望根据您正在寻找的外观和感觉更多地自定义它。
回答by Wouter
You could use something like: http://materialdesigninxaml.net
你可以使用类似的东西:http: //materialdesigninxaml.net
回答by Celso Lívero
This is the default menu, but white, you can change the background color, text font, height, and everything else you want just by editing this style.
这是默认菜单,但是白色,您可以通过编辑此样式来更改背景颜色、文本字体、高度以及您想要的任何其他内容。
Here your MainWindow.xaml
这里你的MainWindow.xaml
<Menu IsMainMenu="True" HorizontalContentAlignment="Left" Background="Transparent" >
<MenuItem Header="File" HorizontalContentAlignment="Left" >
<MenuItem Header="Menu Item 01" Command="{Binding MenuCommand}" CommandParameter="Param01" >
<MenuItem.Icon>
<Image Source="Images/settings.png" Height="20"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Menu Item 02" Command="{Binding MenuCommand}" CommandParameter="Param02" >
<MenuItem.Icon>
<Image Source="Images/settings.png" Height="20"/>
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem Header="LogOff" Command="{Binding MenuCommand}" CommandParameter="LogOff" >
<MenuItem.Icon>
<Image Source="Images/logoff.png" Height="20"/>
</MenuItem.Icon>
</MenuItem>
</MenuItem>
</Menu>
style in app.xamlfile
app.xaml文件中的 样式
<!-- Menu Begin -->
<!-- Menu -->
<Style TargetType="{x:Type Menu}">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.MenuBarBrushKey}}"/>
<Setter Property="FontFamily" Value="{DynamicResource {x:Static SystemFonts.MenuFontFamilyKey}}"/>
<Setter Property="FontSize" Value="{DynamicResource {x:Static SystemFonts.MenuFontSizeKey}}"/>
<Setter Property="FontStyle" Value="{DynamicResource {x:Static SystemFonts.MenuFontStyleKey}}"/>
<Setter Property="FontWeight" Value="{DynamicResource {x:Static SystemFonts.MenuFontWeightKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.MenuTextBrushKey}}"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Menu}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Level 0 -->
<ControlTemplate x:Key="{x:Static MenuItem.TopLevelItemTemplateKey}" TargetType="{x:Type MenuItem}">
<Border x:Name="templateRoot" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<Grid x:Name="Grid" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<ContentPresenter x:Name="Icon" Content="{TemplateBinding Icon}" ContentSource="Icon" HorizontalAlignment="Center" Height="16" Margin="3" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center" Width="16" Visibility="Collapsed"/>
<Path x:Name="GlyphPanel" Data="F1M10,1.2L4.7,9.1 4.5,9.1 0,5.2 1.3,3.5 4.3,6.1 8.3,0 10,1.2z" Fill="{TemplateBinding Foreground}" FlowDirection="LeftToRight" Margin="3" Visibility="Collapsed" VerticalAlignment="Center"/>
<ContentPresenter x:Name="ContentPresenter" ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" Grid.Column="1" ContentStringFormat="{TemplateBinding HeaderStringFormat}" ContentSource="Header" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
<Popup x:Name="PART_Popup" AllowsTransparency="True" Focusable="False" IsOpen="{Binding IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}" PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}" Placement="Bottom" >
<Border x:Name="SubMenuBorder" BorderBrush="#FF999999" BorderThickness="1" Background="White" Padding="2">
<ScrollViewer x:Name="SubMenuScrollViewer" Style="{DynamicResource {ComponentResourceKey ResourceId=MenuScrollViewer, TypeInTargetAssembly={x:Type FrameworkElement}}}">
<Grid x:Name="Grid1" RenderOptions.ClearTypeHint="Enabled">
<Canvas x:Name="Canvas" HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
<Rectangle x:Name="OpaqueRect" Fill="{Binding Background, ElementName=SubMenuBorder}" Height="{Binding ActualHeight, ElementName=SubMenuBorder}" Width="{Binding ActualWidth, ElementName=SubMenuBorder}"/>
</Canvas>
<Rectangle x:Name="Rectangle" Fill="Transparent" HorizontalAlignment="Left" Margin="29,2,0,2" Width="1"/>
<ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Cycle" Grid.IsSharedSizeScope="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" KeyboardNavigation.TabNavigation="Cycle"/>
</Grid>
</ScrollViewer>
</Border>
</Popup>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSuspendingPopupAnimation" Value="True">
<Setter Property="PopupAnimation" TargetName="PART_Popup" Value="None"/>
</Trigger>
<Trigger Property="Icon" Value="{x:Null}">
<Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Visibility" TargetName="GlyphPanel" Value="Visible"/>
<Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
</Trigger>
<Trigger Property="IsHighlighted" Value="True">
<Setter Property="Background" TargetName="templateRoot" Value="#3D26A0DA"/>
<Setter Property="BorderBrush" TargetName="templateRoot" Value="#FF26A0DA"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="TextElement.Foreground" TargetName="templateRoot" Value="#FF707070"/>
<Setter Property="Fill" TargetName="GlyphPanel" Value="#FF707070"/>
</Trigger>
<Trigger Property="CanContentScroll" SourceName="SubMenuScrollViewer" Value="False">
<Setter Property="Canvas.Top" TargetName="OpaqueRect" Value="{Binding VerticalOffset, ElementName=SubMenuScrollViewer}"/>
<Setter Property="Canvas.Left" TargetName="OpaqueRect" Value="{Binding HorizontalOffset, ElementName=SubMenuScrollViewer}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!-- Level 0 -->
<ControlTemplate x:Key="{x:Static MenuItem.TopLevelHeaderTemplateKey}" TargetType="{x:Type MenuItem}">
<Border x:Name="templateRoot" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<Grid x:Name="Grid" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<ContentPresenter x:Name="Icon" Content="{TemplateBinding Icon}" ContentSource="Icon" HorizontalAlignment="Center" Height="16" Margin="3" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center" Width="16" Visibility="Collapsed"/>
<Path x:Name="GlyphPanel" Data="F1M10,1.2L4.7,9.1 4.5,9.1 0,5.2 1.3,3.5 4.3,6.1 8.3,0 10,1.2z" Fill="{TemplateBinding Foreground}" FlowDirection="LeftToRight" Margin="3" Visibility="Collapsed" VerticalAlignment="Center"/>
<ContentPresenter x:Name="ContentPresenter" ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" Grid.Column="1" ContentStringFormat="{TemplateBinding HeaderStringFormat}" ContentSource="Header" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
<Popup x:Name="PART_Popup" AllowsTransparency="True" Focusable="False" IsOpen="{Binding IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}" PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}" Placement="Bottom" >
<Border x:Name="SubMenuBorder" BorderBrush="#FF999999" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.MenuColorKey}}" Padding="2">
<ScrollViewer x:Name="SubMenuScrollViewer" Style="{DynamicResource {ComponentResourceKey ResourceId=MenuScrollViewer, TypeInTargetAssembly={x:Type FrameworkElement}}}">
<Grid x:Name="Grid1" RenderOptions.ClearTypeHint="Enabled">
<Canvas x:Name="Canvas" HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
<Rectangle x:Name="OpaqueRect" Fill="{Binding Background, ElementName=SubMenuBorder}" Height="{Binding ActualHeight, ElementName=SubMenuBorder}" Width="{Binding ActualWidth, ElementName=SubMenuBorder}"/>
</Canvas>
<Rectangle x:Name="Rectangle" Fill="Transparent" HorizontalAlignment="Left" Margin="29,2,0,2" Width="1"/>
<ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Cycle" Grid.IsSharedSizeScope="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" KeyboardNavigation.TabNavigation="Cycle"/>
</Grid>
</ScrollViewer>
</Border>
</Popup>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSuspendingPopupAnimation" Value="True">
<Setter Property="PopupAnimation" TargetName="PART_Popup" Value="None"/>
</Trigger>
<Trigger Property="Icon" Value="{x:Null}">
<Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Visibility" TargetName="GlyphPanel" Value="Visible"/>
<Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
</Trigger>
<Trigger Property="IsHighlighted" Value="True">
<Setter Property="Background" TargetName="templateRoot" Value="#3D26A0DA"/>
<Setter Property="BorderBrush" TargetName="templateRoot" Value="#FF26A0DA"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="TextElement.Foreground" TargetName="templateRoot" Value="#FF707070"/>
<Setter Property="Fill" TargetName="GlyphPanel" Value="#FF707070"/>
</Trigger>
<Trigger Property="CanContentScroll" SourceName="SubMenuScrollViewer" Value="False">
<Setter Property="Canvas.Top" TargetName="OpaqueRect" Value="{Binding VerticalOffset, ElementName=SubMenuScrollViewer}"/>
<Setter Property="Canvas.Left" TargetName="OpaqueRect" Value="{Binding HorizontalOffset, ElementName=SubMenuScrollViewer}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!-- Level 1,2,3,4,... -->
<ControlTemplate x:Key="{x:Static MenuItem.SubmenuHeaderTemplateKey}" TargetType="{x:Type MenuItem}">
<Border x:Name="templateRoot" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<Grid Margin="-1">
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="22" SharedSizeGroup="MenuItemIconColumnGroup" Width="Auto"/>
<ColumnDefinition Width="13"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition SharedSizeGroup="MenuItemIGTColumnGroup" Width="Auto"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<ContentPresenter x:Name="Icon" Content="{TemplateBinding Icon}" ContentSource="Icon" HorizontalAlignment="Center" Height="16" Margin="3" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center" Width="16"/>
<Border x:Name="GlyphPanel" BorderBrush="#FF26A0DA" BorderThickness="1" Background="#3D26A0DA" Height="22" Margin="-1,0,0,0" Visibility="Hidden" VerticalAlignment="Center" Width="22" >
<Path x:Name="Glyph" Data="{DynamicResource ?}" Fill="#FF212121" FlowDirection="LeftToRight" Height="11" Width="9"/>
</Border>
<ContentPresenter ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" Grid.Column="2" ContentStringFormat="{TemplateBinding HeaderStringFormat}" ContentSource="Header" HorizontalAlignment="Left" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center"/>
<TextBlock Grid.Column="4" Margin="{TemplateBinding Padding}" Opacity="0.7" Text="{TemplateBinding InputGestureText}" VerticalAlignment="Center"/>
<Path x:Name="RightArrow" Grid.Column="5" Data="M0,0L4,3.5 0,7z" Fill="#FF212121" HorizontalAlignment="Left" Margin="10,0,0,0" VerticalAlignment="Center"/>
<Popup x:Name="PART_Popup" AllowsTransparency="True" Focusable="False" HorizontalOffset="-2" IsOpen="{Binding IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}" PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}" Placement="Right" VerticalOffset="-3">
<Border x:Name="SubMenuBorder" BorderBrush="#FF999999" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.MenuColorKey}}" Padding="2">
<ScrollViewer x:Name="SubMenuScrollViewer" Style="{DynamicResource {ComponentResourceKey ResourceId=MenuScrollViewer, TypeInTargetAssembly={x:Type FrameworkElement}}}">
<Grid RenderOptions.ClearTypeHint="Enabled">
<Canvas HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
<!--Fill="{Binding Background, ElementName=SubMenuBorder}" White #FFF0F0F0-->
<Rectangle x:Name="OpaqueRect" Fill="{Binding Background, ElementName=SubMenuBorder}" Height="{Binding ActualHeight, ElementName=SubMenuBorder}" Width="{Binding ActualWidth, ElementName=SubMenuBorder}"/>
</Canvas>
<Rectangle Fill="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}" HorizontalAlignment="Left" Margin="29,2,0,2" Width="1"/>
<ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Cycle" Grid.IsSharedSizeScope="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" KeyboardNavigation.TabNavigation="Cycle"/>
</Grid>
</ScrollViewer>
</Border>
</Popup>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSuspendingPopupAnimation" Value="True">
<Setter Property="PopupAnimation" TargetName="PART_Popup" Value="None"/>
</Trigger>
<Trigger Property="Icon" Value="{x:Null}">
<Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Visibility" TargetName="GlyphPanel" Value="Visible"/>
<Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
</Trigger>
<Trigger Property="IsHighlighted" Value="True">
<Setter Property="Background" TargetName="templateRoot" Value="Transparent"/>
<Setter Property="BorderBrush" TargetName="templateRoot" Value="#FF26A0DA"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="TextElement.Foreground" TargetName="templateRoot" Value="#FF707070"/>
<Setter Property="Fill" TargetName="Glyph" Value="#FF707070"/>
<Setter Property="Fill" TargetName="RightArrow" Value="#FF707070"/>
</Trigger>
<Trigger Property="CanContentScroll" SourceName="SubMenuScrollViewer" Value="False">
<Setter Property="Canvas.Top" TargetName="OpaqueRect" Value="{Binding VerticalOffset, ElementName=SubMenuScrollViewer}"/>
<Setter Property="Canvas.Left" TargetName="OpaqueRect" Value="{Binding HorizontalOffset, ElementName=SubMenuScrollViewer}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!-- Level 1,2,3,4,... -->
<ControlTemplate x:Key="{x:Static MenuItem.SubmenuItemTemplateKey}" TargetType="{x:Type MenuItem}">
<Border x:Name="templateRoot" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<Grid Margin="-1">
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="22" SharedSizeGroup="MenuItemIconColumnGroup" Width="Auto"/>
<ColumnDefinition Width="13"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition SharedSizeGroup="MenuItemIGTColumnGroup" Width="Auto"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<ContentPresenter x:Name="Icon" Content="{TemplateBinding Icon}" ContentSource="Icon" HorizontalAlignment="Center" Height="16" Margin="3" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center" Width="16"/>
<Border x:Name="GlyphPanel" BorderBrush="#FF26A0DA" BorderThickness="1" Background="#3D26A0DA" ClipToBounds="False" HorizontalAlignment="Center" Height="22" Margin="-1,0,0,0" Visibility="Hidden" VerticalAlignment="Center" Width="22">
<Path x:Name="Glyph" Data="F1M10,1.2L4.7,9.1 4.5,9.1 0,5.2 1.3,3.5 4.3,6.1 8.3,0 10,1.2z" Fill="#FF212121" FlowDirection="LeftToRight" Height="11" Width="10"/>
</Border>
<ContentPresenter x:Name="menuHeaderContainer" ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" Grid.Column="2" ContentStringFormat="{TemplateBinding HeaderStringFormat}" ContentSource="Header" HorizontalAlignment="Left" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center"/>
<TextBlock x:Name="menuGestureText" Grid.Column="4" Margin="{TemplateBinding Padding}" Opacity="0.7" Text="{TemplateBinding InputGestureText}" VerticalAlignment="Center"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Icon" Value="{x:Null}">
<Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Visibility" TargetName="GlyphPanel" Value="Visible"/>
<Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
</Trigger>
<Trigger Property="IsHighlighted" Value="True">
<Setter Property="Background" TargetName="templateRoot" Value="#3D26A0DA"/>
<Setter Property="BorderBrush" TargetName="templateRoot" Value="#FF26A0DA"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="TextElement.Foreground" TargetName="templateRoot" Value="#FF707070"/>
<Setter Property="Fill" TargetName="Glyph" Value="#FF707070"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsHighlighted" Value="True"/>
<Condition Property="IsEnabled" Value="False"/>
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="templateRoot" Value="#0A000000"/>
<Setter Property="BorderBrush" TargetName="templateRoot" Value="#21000000"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!-- Menu End -->
回答by Markus
I would create the menu with XAML
我会用 XAML 创建菜单
XAML of Page something like this:
页面的 XAML 是这样的:
<Window.Resources>
<Style TargetType="TextBlock">
<Setter Property="Margin" Value="10" />
<Setter Property="FontSize" Value="15" />
<Setter Property="Foreground" Value="White" />
</Style>
</Window.Resources>
<Grid x:Name="Content">
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Background="CornflowerBlue">
<TextBlock Text="Menu1" MouseLeftButtonDown="OnMouseLeftButtonDown" />
<TextBlock Text="Menu2" MouseLeftButtonDown="OnMouseLeftButtonDown" />
<TextBlock Text="Menu3" MouseLeftButtonDown="OnMouseLeftButtonDown" />
</StackPanel>
<Border Grid.Row="1" Background="Bisque"></Border>
</Grid>
</Grid>
And in Code:
在代码中:
private void OnMouseLeftButtonDown(object sender, MouseEventArgs e) {
var textBlock = sender as TextBlock;
if (textBlock == null) return;
var relativePoint = VisualTreeHelper.GetOffset(textBlock);//textBlock.TransformToAncestor(Content).Transform(new Point(0, 0));
//Almost invisible Background - If the user clicks it the menu is hidden
var back = new Border{Background = new SolidColorBrush(Color.FromArgb(1,255,255,255))};
back.MouseLeftButtonDown += (o, args) => {
Content.Children.Remove(back.Tag as UIElement);
Content.Children.Remove(back);
};
Content.Children.Add(back);
//Build menu
var menu = new Border{Background = new SolidColorBrush(Colors.White), Width = 200, Height = 500, BorderBrush = new SolidColorBrush(Colors.Gray), BorderThickness = new Thickness(1), HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Top};
back.Tag = menu;
menu.RenderTransform = new TranslateTransform(relativePoint.X, relativePoint.Y + textBlock.ActualHeight + 5);
//Do some more styling
//Fill Menu here according to the tag of the TextBlock (switch(textBlock.Tag){...} or use a predefined view
Content.Children.Add(menu);
//Hide the Menu on click - TODO Implement logic to hide menu if a MenuItem was clicked...
menu.MouseLeftButtonDown += (o, args) => {
Content.Children.Remove(back.Tag as UIElement);
Content.Children.Remove(back);
};
}
OK, this is a very basic example and needs a lot of improvement but I think you can work on it...
好的,这是一个非常基本的示例,需要大量改进,但我认为您可以对其进行处理...


![wpf 解析值后遇到意外字符:6. 路径 '[0]](/res/img/loading.gif)