4

WPF实现Win10汉堡菜单

 2 years ago
source link: https://www.cnblogs.com/yanjinhua/p/15419577.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

WPF实现Win10汉堡菜单

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

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

987480-20211018102114531-308925955.jpg

 由于在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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK