- A+
WPF开发者QQ群: 340500857 | 微信群 -> 进入公众号主页 加入组织
前言
有小伙伴提出需要实现Win10汉堡菜单效果。
由于在WPF中没有现成的类似UWP的汉堡菜单,所以我们自己实现一个。
一、创建 Win10Menu.cs 菜单继承 ContentControl 代码如下。
1、IsOpen :判定是否展开、收起 。
2、Content :存放菜单集合。
3、SelectionIndicatorColor :选中菜单状态栏颜色。
4、MenuItemForeground:菜单集字体颜色。
using System.Collections.Generic; using System.Windows; using System.Windows.Controls; using System.Windows.Media; namespace WPFDevelopers.Controls { public class Win10Menu : ContentControl { public new List<Win10MenuItem> Content { get { return (List<Win10MenuItem>)GetValue(ContentProperty); } set { SetValue(ContentProperty, value); } } public new static readonly DependencyProperty ContentProperty = DependencyProperty.Register("Content", typeof(List<Win10MenuItem>), typeof(Win10Menu),new FrameworkPropertyMetadata(null)); static Win10Menu() { DefaultStyleKeyProperty.OverrideMetadata(typeof(Win10Menu), new FrameworkPropertyMetadata(typeof(Win10Menu))); } public override void BeginInit() { Content = new List<Win10MenuItem>(); base.BeginInit(); } public bool IsOpen { get { return (bool)GetValue(IsOpenProperty); } set { SetValue(IsOpenProperty, value); } } public static readonly DependencyProperty IsOpenProperty = DependencyProperty.Register("IsOpen", typeof(bool), typeof(Win10Menu), new PropertyMetadata(true)); public System.Windows.Media.Brush MenuIconColor { get { return (System.Windows.Media.Brush)GetValue(MenuIconColorProperty); } set { SetValue(MenuIconColorProperty, value); } } public static readonly DependencyProperty MenuIconColorProperty = DependencyProperty.Register("MenuIconColor", typeof(System.Windows.Media.Brush), typeof(Win10Menu), new PropertyMetadata(Brushes.White)); public Brush SelectionIndicatorColor { get { return (Brush)GetValue(SelectionIndicatorColorProperty); } set { SetValue(SelectionIndicatorColorProperty, value); } } public static readonly DependencyProperty SelectionIndicatorColorProperty = DependencyProperty.Register("SelectionIndicatorColor", typeof(Brush), typeof(Win10Menu), new PropertyMetadata(Brushes.Red)); public Brush MenuItemForeground { get { return (Brush)GetValue(MenuItemForegroundProperty); } set { SetValue(MenuItemForegroundProperty, value); } } public static readonly DependencyProperty MenuItemForegroundProperty = DependencyProperty.Register("MenuItemForeground", typeof(Brush), typeof(Win10Menu), new PropertyMetadata(Brushes.Transparent)); } }
二、创建 Win10Menu.xaml 为 Win10Menu.cs 进行布局 代码如下
Win10Menu.xaml 思路如下
1、ToggleButton :控制IsChecked动画如下
IsOpen = False:DoubleAnimation修改controls:Win10Menu的Width为 180。
IsOpen = True :DoubleAnimation修改controls:Win10Menu的Width为 50。
2、ListBox:ItemsSource="{TemplateBinding Content}"展示菜单集合。
需注意如下
ScrollViewer.HorizontalScrollBarVisibility="Disabled",不然当Win10Menu的Width 为50时会出现滚动条。
<Style TargetType="ToggleButton"> <Setter Property="IsChecked" Value="False"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ToggleButton}"> <Grid Background="{TemplateBinding Background}"> <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" /> </Grid> </ControlTemplate> </Setter.Value> </Setter> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="Opacity" Value="0.8" /> <Setter Property="Cursor" Value="Hand" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ToggleButton}"> <Border Background="{TemplateBinding Background}" BorderBrush="Black" BorderThickness="1"> <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" /> </Border> </ControlTemplate> </Setter.Value> </Setter> </Trigger> </Style.Triggers> </Style> <Style TargetType="ListBox"> <Setter Property="Background" Value="Transparent" /> <Setter Property="BorderBrush" Value="Transparent" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate> <ScrollViewer> <ItemsPresenter Margin="0" /> </ScrollViewer> </ControlTemplate> </Setter.Value> </Setter> </Style> <Style TargetType="controls:Win10Menu"> <Setter Property="Width" Value="50"/> <Setter Property="Visibility" Value="Visible"/> <Setter Property="IsOpen" Value="True"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="controls:Win10Menu"> <Grid Background="{TemplateBinding Background}"> <ToggleButton HorizontalAlignment="Left" Background="#333" VerticalAlignment="Top" Height="40" Width="50" IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type controls:Win10Menu}}, Path=IsOpen}"> <Path HorizontalAlignment="Center" VerticalAlignment="Center" Stretch="Uniform" Width="20" Fill="{TemplateBinding MenuIconColor}" Data="{StaticResource PathMenu}"/> </ToggleButton> <ListBox ItemsSource="{TemplateBinding Content}" HorizontalAlignment="Left" Margin="0,40,0,0" VerticalAlignment="Top" ScrollViewer.HorizontalScrollBarVisibility="Disabled" SelectedIndex="0"/> </Grid> </ControlTemplate> </Setter.Value> </Setter> <Style.Triggers> <Trigger Property="IsOpen" Value="False"> <Trigger.EnterActions> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetProperty="Width" To="180" Duration="0:0:0.2"/> </Storyboard> </BeginStoryboard> </Trigger.EnterActions> <Trigger.ExitActions> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetProperty="Width" To="50" Duration="0:0:0.2"/> </Storyboard> </BeginStoryboard> </Trigger.ExitActions> </Trigger> </Style.Triggers> </Style>
三、创建 Win10MenuItem.cs 继承 ListBoxItem 代码如下。
Win10MenuItem.cs 思路如下
1、Text 菜单文本内容展示。
2、Icon 菜单图标为ImageSource类型。
3、SelectionIndicatorColor选中的侧边状态颜色。
4、SelectionCommand 选中事件。
using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; namespace WPFDevelopers.Controls { public class Win10MenuItem : ListBoxItem { static Win10MenuItem() { DefaultStyleKeyProperty.OverrideMetadata(typeof(Win10MenuItem), new FrameworkPropertyMetadata(typeof(Win10MenuItem))); } public string Text { get { return (string)GetValue(TextProperty); } set { SetValue(TextProperty, value); } } public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(Win10MenuItem), new PropertyMetadata(string.Empty)); public ImageSource Icon { get { return (ImageSource)GetValue(IconProperty); } set { SetValue(IconProperty, value); } } public static readonly DependencyProperty IconProperty = DependencyProperty.Register("Icon", typeof(ImageSource), typeof(Win10MenuItem), new PropertyMetadata(null)); public Brush SelectionIndicatorColor { get { return (Brush)GetValue(SelectionIndicatorColorProperty); } set { SetValue(SelectionIndicatorColorProperty, value); } } public static readonly DependencyProperty SelectionIndicatorColorProperty = DependencyProperty.Register("SelectionIndicatorColor", typeof(Brush), typeof(Win10MenuItem), new PropertyMetadata(Brushes.Blue)); public ICommand SelectionCommand { get { return (ICommand)GetValue(SelectionCommandProperty); } set { SetValue(SelectionCommandProperty, value); } } public static readonly DependencyProperty SelectionCommandProperty = DependencyProperty.Register("SelectionCommand", typeof(ICommand), typeof(Win10MenuItem), new PropertyMetadata(null)); } }
四、创建 Win10MenuItem.xaml 为 Win10MenuItem.cs 进行布局 代码如下
<Style x:Key="ButtonFocusVisual"> <Setter Property="Control.Template"> <Setter.Value> <ControlTemplate> <Border> <Rectangle Margin="2" StrokeThickness="1" Stroke="#60000000" StrokeDashArray="1 2"/> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> <!-- Fill Brushes --> <SolidColorBrush x:Key="NormalBrush" Color="Transparent" /> <SolidColorBrush x:Key="DarkBrush" Color="#ddd" /> <SolidColorBrush x:Key="PressedBrush" Color="#80FFFFFF" /> <SolidColorBrush x:Key="DisabledForegroundBrush" Color="Transparent" /> <SolidColorBrush x:Key="DisabledBackgroundBrush" Color="Transparent" /> <!-- Border Brushes --> <SolidColorBrush x:Key="NormalBorderBrush" Color="Transparent" /> <SolidColorBrush x:Key="PressedBorderBrush" Color="Transparent" /> <SolidColorBrush x:Key="DefaultedBorderBrush" Color="Transparent" /> <SolidColorBrush x:Key="DisabledBorderBrush" Color="Transparent" /> <Style TargetType="Button"> <Setter Property="SnapsToDevicePixels" Value="true"/> <Setter Property="OverridesDefaultStyle" Value="true"/> <Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}"/> <Setter Property="MinHeight" Value="23"/> <Setter Property="MinWidth" Value="75"/> <Setter Property="Cursor" Value="Hand" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Button"> <Border x:Name="Border" CornerRadius="0" BorderThickness="0" Background="{StaticResource NormalBrush}" BorderBrush="{StaticResource NormalBorderBrush}"> <ContentPresenter HorizontalAlignment="Stretch" VerticalAlignment="Stretch" RecognizesAccessKey="True"/> </Border> <ControlTemplate.Triggers> <Trigger Property="IsKeyboardFocused" Value="true"> <Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource DefaultedBorderBrush}" /> </Trigger> <Trigger Property="IsDefaulted" Value="true"> <Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource DefaultedBorderBrush}" /> </Trigger> <Trigger Property="IsMouseOver" Value="true"> <Setter TargetName="Border" Property="Background" Value="{StaticResource DarkBrush}" /> </Trigger> <Trigger Property="IsPressed" Value="true"> <Setter TargetName="Border" Property="Background" Value="{StaticResource PressedBrush}" /> <Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource PressedBorderBrush}" /> </Trigger> <Trigger Property="IsEnabled" Value="false"> <Setter TargetName="Border" Property="Background" Value="{StaticResource DisabledBackgroundBrush}" /> <Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource DisabledBorderBrush}" /> <Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> <Style TargetType="controls:Win10MenuItem"> <Setter Property="HorizontalContentAlignment" Value="Stretch" /> <Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type controls:Win10Menu}}, Path=MenuItemForeground}"/> <Setter Property="SelectionIndicatorColor" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type controls:Win10Menu}}, Path=SelectionIndicatorColor}"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="controls:Win10MenuItem"> <Button x:Name="PART_Button" Height="44" Command="{TemplateBinding SelectionCommand}" ToolTip="{TemplateBinding Text}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="5"/> <ColumnDefinition/> </Grid.ColumnDefinitions> <Grid Grid.ColumnSpan="2"> <Grid Margin="0" Width="300"> <Grid.ColumnDefinitions> <ColumnDefinition Width="45"/> <ColumnDefinition/> </Grid.ColumnDefinitions> <Image Grid.Column="0" Source="{TemplateBinding Icon}" Margin="10,5,5,5"/> <TextBlock Text="{TemplateBinding Text}" Grid.Column="1" Margin="10,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Center" FontSize="{StaticResource TitleFontSize}" Foreground="{TemplateBinding Foreground}" TextWrapping="Wrap"/> </Grid> </Grid> <Grid Name="PART_ItemSelectedIndicator" Grid.Column="0" Background="{TemplateBinding SelectionIndicatorColor}" Visibility="Collapsed" /> </Grid> </Button> <ControlTemplate.Triggers> <Trigger Property="IsSelected" Value="True"> <Setter TargetName="PART_ItemSelectedIndicator" Property="Visibility" Value="Visible" /> </Trigger> <Trigger SourceName="PART_Button" Property="IsPressed" Value="True"> <Trigger.ExitActions> <BeginStoryboard> <Storyboard> <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsSelected"> <DiscreteBooleanKeyFrame KeyTime="00:00:00" Value="True" /> </BooleanAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </Trigger.ExitActions> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>
五、创建Win10MenuExample.xaml代码如下
Win10MenuExample.xaml实现思路如下
1、Grid布局分为两列设置第零列Width为Auto自适应。
2、第零列为Win10menu。
3、第一列为Frame设置NavigationUIVisibility="Hidden"
<UserControl x:Class="WPFDevelopers.Samples.ExampleViews.Win10Menu.Win10MenuExample" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:WPFDevelopers.Samples.ExampleViews.Win10Menu" xmlns:wpfdev="https://github.com/yanjinhuagood/WPFDevelopers" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <Grid Background="#FF7B7BFF"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition/> </Grid.ColumnDefinitions> <wpfdev:Win10Menu Background="#eee" SelectionIndicatorColor="{StaticResource PrimaryPressedSolidColorBrush}" MenuItemForeground="{StaticResource BlackSolidColorBrush}" HorizontalAlignment="Left"> <wpfdev:Win10Menu.Content> <wpfdev:Win10MenuItem Icon="pack://application:,,,/Images/CircularMenu/2.png" Text="主页" SelectionCommand="{Binding HomeCommand,RelativeSource={RelativeSource AncestorType=local:Win10MenuExample}}"/> <wpfdev:Win10MenuItem Icon="pack://application:,,,/Images/CircularMenu/4.png" Text="Edge" SelectionCommand="{Binding EdgeCommand,RelativeSource={RelativeSource AncestorType=local:Win10MenuExample}}"/> <wpfdev:Win10MenuItem Icon="pack://application:,,,/Images/CircularMenu/1.png" Text="云盘" SelectionCommand="{Binding CloudCommand,RelativeSource={RelativeSource AncestorType=local:Win10MenuExample}}"/> <wpfdev:Win10MenuItem Icon="pack://application:,,,/Images/CircularMenu/8.png" Text="邮件" SelectionCommand="{Binding MailCommand,RelativeSource={RelativeSource AncestorType=local:Win10MenuExample}}"/> <wpfdev:Win10MenuItem Icon="pack://application:,,,/Images/CircularMenu/6.png" Text="视频" SelectionCommand="{Binding VideoCommand,RelativeSource={RelativeSource AncestorType=local:Win10MenuExample}}"/> </wpfdev:Win10Menu.Content> </wpfdev:Win10Menu> <Frame Name="myFrame" Grid.Column="1" Margin="0,40,0,0" NavigationUIVisibility="Hidden"></Frame> </Grid> </UserControl>
六、创建Win10MenuExample.xaml.cs代码如下
Win10MenuExample.xaml实现思路如下
1、定义List<Uri>赋值集合为菜单需要跳转的页面。
2、构造为myFrame.Navigate(_uriList[0]);第零页。
using System; using System.Collections.Generic; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using WPFDevelopers.Samples.Helpers; namespace WPFDevelopers.Samples.ExampleViews.Win10Menu { /// <summary> /// Win10MenuExample.xaml 的交互逻辑 /// </summary> public partial class Win10MenuExample : UserControl { private List<Uri> _uriList = new List<Uri>() { new Uri("ExampleViews/Win10Menu/HomePage.xaml",UriKind.Relative), new Uri("ExampleViews/Win10Menu/EdgePage.xaml",UriKind.Relative), }; public Win10MenuExample() { InitializeComponent(); myFrame.Navigate(_uriList[0]); } public ICommand HomeCommand => new RelayCommand(obj => { myFrame.Navigate(_uriList[0]); }); public ICommand EdgeCommand => new RelayCommand(obj => { myFrame.Navigate(_uriList[1]); }); public ICommand CloudCommand => new RelayCommand(obj => { MessageBox.Show("点击了云盘"); }); public ICommand MailCommand => new RelayCommand(obj => { MessageBox.Show("点击了邮件"); }); public ICommand VideoCommand => new RelayCommand(obj => { MessageBox.Show("点击了视频"); }); } }
效果预览
更多教程欢迎关注微信公众号:加微信群限时
WPF开发者QQ群: 340500857
blogs: https://www.cnblogs.com/yanjinhua/p/14345136.html
源码Github:https://github.com/yanjinhuagood/WPFDevelopers.git
gitee:https://gitee.com/yanjinhua/WPFDevelopers.git