WPF实现Win10汉堡菜单

  • A+
所属分类:.NET技术
摘要

WPF开发者QQ群: 340500857  | 微信群 -> 进入公众号主页 加入组织

WPF开发者QQ群: 340500857  | 微信群 -> 进入公众号主页 加入组织

前言

      有小伙伴提出需要实现Win10汉堡菜单效果。      

WPF实现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:Win10MenuWidth为 180。

 IsOpen = TrueDoubleAnimation修改controls:Win10MenuWidth为 50。

 2、ListBox:ItemsSource="{TemplateBinding Content}"展示菜单集合。          

需注意如下 

ScrollViewer.HorizontalScrollBarVisibility="Disabled",不然当Win10MenuWidth 为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布局分为两列设置第零列WidthAuto自适应。

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实现Win10汉堡菜单

 

更多教程欢迎关注微信公众号:加微信群限时

WPF实现Win10汉堡菜单

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