?分享一個WPF 實現抽屜菜單
抽屜菜單
作者:WPFDevelopersOrg
原文鏈接:https://github.com/WPFDevelopersOrg/WPFDevelopers
框架使用大于等于
.NET40
;Visual Studio 2022
;項目使用 MIT 開源許可協議;
更多效果可以通過GitHub[1]|碼云[2]下載代碼;
由于在WPF中沒有現成的類似UWP的抽屜菜單,所以我們自己實現一個。
1) DrawerMenu.cs 代碼如下。
using?System.Collections.Generic;
using?System.Windows;
using?System.Windows.Controls;
using?System.Windows.Media;namespace?WPFDevelopers.Controls
{public?class?DrawerMenu?:?ContentControl{public?new?static?readonly?DependencyProperty?ContentProperty?=DependencyProperty.Register("Content",?typeof(List<DrawerMenuItem>),?typeof(DrawerMenu),new?FrameworkPropertyMetadata(null));public?static?readonly?DependencyProperty?IsOpenProperty?=DependencyProperty.Register("IsOpen",?typeof(bool),?typeof(DrawerMenu),?new?PropertyMetadata(true));public?static?readonly?DependencyProperty?MenuIconColorProperty?=DependencyProperty.Register("MenuIconColor",?typeof(Brush),?typeof(DrawerMenu),new?PropertyMetadata(Brushes.White));public?static?readonly?DependencyProperty?SelectionIndicatorColorProperty?=DependencyProperty.Register("SelectionIndicatorColor",?typeof(Brush),?typeof(DrawerMenu),new?PropertyMetadata(DrawingContextHelper.Brush));public?static?readonly?DependencyProperty?MenuItemForegroundProperty?=DependencyProperty.Register("MenuItemForeground",?typeof(Brush),?typeof(DrawerMenu),new?PropertyMetadata(Brushes.Transparent));static?DrawerMenu(){DefaultStyleKeyProperty.OverrideMetadata(typeof(DrawerMenu),new?FrameworkPropertyMetadata(typeof(DrawerMenu)));}public?new?List<DrawerMenuItem>?Content{get?=>?(List<DrawerMenuItem>)GetValue(ContentProperty);set?=>?SetValue(ContentProperty,?value);}public?bool?IsOpen{get?=>?(bool)GetValue(IsOpenProperty);set?=>?SetValue(IsOpenProperty,?value);}public?Brush?MenuIconColor{get?=>?(Brush)GetValue(MenuIconColorProperty);set?=>?SetValue(MenuIconColorProperty,?value);}public?Brush?SelectionIndicatorColor{get?=>?(Brush)GetValue(SelectionIndicatorColorProperty);set?=>?SetValue(SelectionIndicatorColorProperty,?value);}public?Brush?MenuItemForeground{get?=>?(Brush)GetValue(MenuItemForegroundProperty);set?=>?SetValue(MenuItemForegroundProperty,?value);}public?override?void?BeginInit(){Content?=?new?List<DrawerMenuItem>();base.BeginInit();}}
}
2) DrawerMenuItem.cs 代碼如下。
using?System.Windows;
using?System.Windows.Controls;
using?System.Windows.Input;
using?System.Windows.Media;namespace?WPFDevelopers.Controls
{public?class?DrawerMenuItem?:?ListBoxItem{public?static?readonly?DependencyProperty?TextProperty?=DependencyProperty.Register("Text",?typeof(string),?typeof(DrawerMenuItem),new?PropertyMetadata(string.Empty));public?static?readonly?DependencyProperty?IconProperty?=DependencyProperty.Register("Icon",?typeof(ImageSource),?typeof(DrawerMenuItem),new?PropertyMetadata(null));public?static?readonly?DependencyProperty?SelectionIndicatorColorProperty?=DependencyProperty.Register("SelectionIndicatorColor",?typeof(Brush),?typeof(DrawerMenuItem),new?PropertyMetadata(DrawingContextHelper.Brush));public?static?readonly?DependencyProperty?SelectionCommandProperty?=DependencyProperty.Register("SelectionCommand",?typeof(ICommand),?typeof(DrawerMenuItem),new?PropertyMetadata(null));static?DrawerMenuItem(){DefaultStyleKeyProperty.OverrideMetadata(typeof(DrawerMenuItem),new?FrameworkPropertyMetadata(typeof(DrawerMenuItem)));}public?string?Text{get?=>?(string)GetValue(TextProperty);set?=>?SetValue(TextProperty,?value);}public?ImageSource?Icon{get?=>?(ImageSource)GetValue(IconProperty);set?=>?SetValue(IconProperty,?value);}public?Brush?SelectionIndicatorColor{get?=>?(Brush)GetValue(SelectionIndicatorColorProperty);set?=>?SetValue(SelectionIndicatorColorProperty,?value);}public?ICommand?SelectionCommand{get?=>?(ICommand)GetValue(SelectionCommandProperty);set?=>?SetValue(SelectionCommandProperty,?value);}}
}
3) DrawerMenu.xaml 代碼如下。
<ResourceDictionary?xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:po="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"xmlns:controls="clr-namespace:WPFDevelopers.Controls"><ResourceDictionary.MergedDictionaries><ResourceDictionary?Source="Basic/ControlBasic.xaml"/></ResourceDictionary.MergedDictionaries><Style?x:Key="DrawerMenuToggleButton"?TargetType="ToggleButton"?BasedOn="{StaticResource?ControlBasicStyle}"><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}"><BorderBackground="{TemplateBinding?Background}"BorderBrush="Black"BorderThickness="1"><ContentPresenter?HorizontalAlignment="Center"?VerticalAlignment="Center"?/></Border></ControlTemplate></Setter.Value></Setter></Trigger></Style.Triggers></Style><Style?x:Key="DrawerMenuListBox"?TargetType="ListBox"?BasedOn="{StaticResource?ControlBasicStyle}"><Setter?Property="Background"?Value="Transparent"?/><Setter?Property="BorderBrush"?Value="Transparent"?/><Setter?Property="BorderThickness"?Value="0"/><Setter?Property="Template"><Setter.Value><ControlTemplate><ScrollViewer><ItemsPresenter?Margin="0"?/></ScrollViewer></ControlTemplate></Setter.Value></Setter></Style><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"??po:Freeze="True"/><SolidColorBrush?x:Key="DarkBrush"?Color="#ddd"??po:Freeze="True"/><SolidColorBrush?x:Key="PressedBrush"?Color="#80FFFFFF"??po:Freeze="True"/><SolidColorBrush?x:Key="DisabledForegroundBrush"?Color="Transparent"??po:Freeze="True"/><SolidColorBrush?x:Key="DisabledBackgroundBrush"?Color="Transparent"??po:Freeze="True"/><!--?Border?Brushes?--><SolidColorBrush?x:Key="NormalBorderBrush"?Color="Transparent"??po:Freeze="True"/><SolidColorBrush?x:Key="PressedBorderBrush"?Color="Transparent"??po:Freeze="True"/><SolidColorBrush?x:Key="DefaultedBorderBrush"?Color="Transparent"??po:Freeze="True"/><SolidColorBrush?x:Key="DisabledBorderBrush"?Color="Transparent"??po:Freeze="True"/><Style?x:Key="DrawerMenuItemButtonStyle"?TargetType="Button"?BasedOn="{StaticResource?ControlBasicStyle}"><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="Transparent"BorderBrush="Transparent"><ContentPresenter?HorizontalAlignment="Stretch"VerticalAlignment="Stretch"RecognizesAccessKey="True"/></Border><ControlTemplate.Triggers><Trigger?Property="IsKeyboardFocused"?Value="true"><Setter?TargetName="Border"?Property="BorderBrush"?Value="{DynamicResource?DefaultedBorderBrush}"?/></Trigger><Trigger?Property="IsDefaulted"?Value="true"><Setter?TargetName="Border"?Property="BorderBrush"?Value="{DynamicResource?DefaultedBorderBrush}"?/></Trigger><Trigger?Property="IsMouseOver"?Value="true"><Setter?TargetName="Border"?Property="Background"?Value="{DynamicResource?DarkBrush}"?/></Trigger><Trigger?Property="IsPressed"?Value="true"><Setter?TargetName="Border"?Property="Background"?Value="{DynamicResource?PressedBrush}"?/><Setter?TargetName="Border"?Property="BorderBrush"?Value="{DynamicResource?PressedBorderBrush}"?/></Trigger><Trigger?Property="IsEnabled"?Value="false"><Setter?TargetName="Border"?Property="Background"?Value="{DynamicResource?DisabledBackgroundBrush}"?/><Setter?TargetName="Border"?Property="BorderBrush"?Value="{DynamicResource?DisabledBorderBrush}"?/><Setter?Property="Foreground"?Value="{DynamicResource?DisabledForegroundBrush}"/></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></Style><Style?TargetType="controls:DrawerMenuItem"><Setter?Property="HorizontalContentAlignment"?Value="Stretch"?/><Setter?Property="Foreground"?Value="{Binding?RelativeSource={RelativeSource?AncestorType={x:Type?controls:DrawerMenu}},?Path=MenuItemForeground}"/><Setter?Property="SelectionIndicatorColor"?Value="{Binding?RelativeSource={RelativeSource?AncestorType={x:Type?controls:DrawerMenu}},?Path=SelectionIndicatorColor}"/><Setter?Property="Template"><Setter.Value><ControlTemplate?TargetType="controls:DrawerMenuItem"><Button?x:Name="PART_Button"?Height="44"Command="{TemplateBinding?SelectionCommand}"?ToolTip="{TemplateBinding?Text}"HorizontalContentAlignment="Stretch"?VerticalContentAlignment="Stretch"Style="{StaticResource?DrawerMenuItemButtonStyle}"><Grid><Grid.ColumnDefinitions><ColumnDefinition?Width="5"/><ColumnDefinition/></Grid.ColumnDefinitions><Grid?Grid.ColumnSpan="2"><Grid?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><Style?TargetType="controls:DrawerMenu"><Setter?Property="Width"?Value="50"/><Setter?Property="Visibility"?Value="Visible"/><Setter?Property="IsOpen"?Value="True"/><Setter?Property="Template"><Setter.Value><ControlTemplate?TargetType="controls:DrawerMenu"><Grid?Background="{TemplateBinding?Background}"><ToggleButton?HorizontalAlignment="Left"?Background="#333"VerticalAlignment="Top"?Height="40"?Width="50"IsChecked="{Binding?RelativeSource={RelativeSource?AncestorType={x:Type?controls:DrawerMenu}},?Path=IsOpen}"Style="{StaticResource?DrawerMenuToggleButton}"><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"?Style="{StaticResource?DrawerMenuListBox}"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>
</ResourceDictionary>
4) DrawerMenuExample.xaml 代碼如下。
<UserControl?x:Class="WPFDevelopers.Samples.ExampleViews.DrawerMenu.DrawerMenuExample"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.DrawerMenu"xmlns:wpfdev="https://github.com/WPFDevelopersOrg/WPFDevelopers"mc:Ignorable="d"?d:DesignHeight="450"?d:DesignWidth="800"><Grid?Background="#FF7B7BFF"><Grid.ColumnDefinitions><ColumnDefinition??Width="Auto"/><ColumnDefinition/></Grid.ColumnDefinitions><wpfdev:DrawerMenu?Background="#eee"SelectionIndicatorColor="{StaticResource?PrimaryPressedSolidColorBrush}"?MenuItemForeground="{StaticResource?BlackSolidColorBrush}"?HorizontalAlignment="Left"><wpfdev:DrawerMenu.Content><wpfdev:DrawerMenuItem?Icon="pack://application:,,,/Images/CircularMenu/2.png"?Text="主頁"SelectionCommand="{Binding?HomeCommand,RelativeSource={RelativeSource?AncestorType=local:DrawerMenuExample}}"/><wpfdev:DrawerMenuItem?Icon="pack://application:,,,/Images/CircularMenu/4.png"?Text="Edge"SelectionCommand="{Binding?EdgeCommand,RelativeSource={RelativeSource?AncestorType=local:DrawerMenuExample}}"/><wpfdev:DrawerMenuItem?Icon="pack://application:,,,/Images/CircularMenu/1.png"?Text="云盤"SelectionCommand="{Binding?CloudCommand,RelativeSource={RelativeSource?AncestorType=local:DrawerMenuExample}}"/><wpfdev:DrawerMenuItem?Icon="pack://application:,,,/Images/CircularMenu/8.png"?Text="郵件"SelectionCommand="{Binding?MailCommand,RelativeSource={RelativeSource?AncestorType=local:DrawerMenuExample}}"/><wpfdev:DrawerMenuItem?Icon="pack://application:,,,/Images/CircularMenu/6.png"?Text="視頻"SelectionCommand="{Binding?VideoCommand,RelativeSource={RelativeSource?AncestorType=local:DrawerMenuExample}}"/></wpfdev:DrawerMenu.Content></wpfdev:DrawerMenu><Frame?Name="myFrame"?Grid.Column="1"?Margin="0,40,0,0"NavigationUIVisibility="Hidden"></Frame></Grid>
</UserControl>
5) DrawerMenuExample.xaml.cs 代碼如下。
using?System;
using?System.Collections.Generic;
using?System.Linq;
using?System.Windows;
using?System.Windows.Controls;
using?System.Windows.Input;
using?System.Windows.Media;
using?WPFDevelopers.Samples.Helpers;namespace?WPFDevelopers.Samples.ExampleViews.DrawerMenu
{///?<summary>///?Win10MenuExample.xaml?的交互邏輯///?</summary>public?partial?class?DrawerMenuExample?:?UserControl{private?List<Uri>?_uriList?=?new?List<Uri>(){new?Uri("ExampleViews/DrawerMenu/HomePage.xaml",UriKind.Relative),new?Uri("ExampleViews/DrawerMenu/EdgePage.xaml",UriKind.Relative),};public?DrawerMenuExample(){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?=>{WPFDevelopers.Minimal.Controls.MessageBox.Show("點擊了云盤","提示");});public?ICommand?MailCommand?=>?new?RelayCommand(obj?=>{WPFDevelopers.Minimal.Controls.MessageBox.Show("點擊了郵件","提示");});public?ICommand?VideoCommand?=>?new?RelayCommand(obj?=>{WPFDevelopers.Minimal.Controls.MessageBox.Show("點擊了視頻","提示");});}
}
6) HomePage.xaml.cs 代碼如下。
<Page?x:Class="WPFDevelopers.Samples.ExampleViews.DrawerMenu.HomePage"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.DrawerMenu"mc:Ignorable="d"?d:DesignHeight="450"?d:DesignWidth="800"Title="HomePage"?Background="{StaticResource?PrimaryTextSolidColorBrush}"><Grid><TextBlock?VerticalAlignment="Center"HorizontalAlignment="Center"Width="400"?TextAlignment="Center"TextWrapping="Wrap"Margin="0,0,0,40"FontSize="{StaticResource?NormalFontSize}"><Run?Foreground="White">Home</Run><Run?Text="微信公眾號?WPFDevelopers"?FontSize="40"Foreground="#A9CC32"?FontWeight="Bold"></Run><LineBreak/><Hyperlink?NavigateUri="https://github.com/WPFDevelopersOrg/WPFDevelopers.git"RequestNavigate="GithubHyperlink_RequestNavigate">?Github?源代碼</Hyperlink><Run/><Run/><Run/><Hyperlink?NavigateUri="https://gitee.com/yanjinhua/WPFDevelopers.git"RequestNavigate="GiteeHyperlink_RequestNavigate">?碼云源代碼</Hyperlink></TextBlock></Grid>
</Page>
7) EdgePage.xaml.cs 代碼如下。
<Page?x:Class="WPFDevelopers.Samples.ExampleViews.DrawerMenu.EdgePage"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.DrawerMenu"mc:Ignorable="d"?d:DesignHeight="450"?d:DesignWidth="800"Title="EdgePage"??Background="{DynamicResource?PrimaryPressedSolidColorBrush}"><Grid><StackPanel?VerticalAlignment="Center"Margin="0,0,0,40"><Image?Source="pack://application:,,,/Images/CircularMenu/4.png"?Stretch="Uniform"Width="50"/><TextBlock?VerticalAlignment="Center"HorizontalAlignment="Center"TextAlignment="Center"Foreground="White"Text="即將跳轉至Edge瀏覽器"FontSize="{StaticResource?TitleFontSize}"Padding="0,10"></TextBlock></StackPanel></Grid>
</Page>
參考①[3]參考②[4]
參考資料
[1]
GitHub: https://github.com/WPFDevelopersOrg/WPFDevelopers
[2]碼云: https://github.com/WPFDevelopersOrg/WPFDevelopers
[3]參考①: https://github.com/WPFDevelopersOrg/WPFDevelopers/tree/master/src/WPFDevelopers/Controls/DrawerMenu
[4]參考②: https://gitee.com/WPFDevelopersOrg/WPFDevelopers/tree/master/src/WPFDevelopers/Controls/DrawerMenu