zoukankan      html  css  js  c++  java
  • WPF实现Win10汉堡菜单

    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: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开发者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

     

  • 相关阅读:
    ubuntu下解决无法解析或打开软件包列表或状态文件的问题
    linux 解除文件root权限限制
    查看linux设备信息的命令
    R系安装rpm包
    重启窗口管理器
    内存泄漏如何定位?
    双屏显示,HDMI可以正常显示,lvds不显示
    避免linux下log在/var/log/messages 中重复输出的办法
    debian编包成功后,想要修改的文件的内容没有变化
    linux terminal 显示不全 将log内容打印出来
  • 原文地址:https://www.cnblogs.com/yanjinhua/p/15419577.html
Copyright © 2011-2022 走看看