WPF实现环(圆)形菜单

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

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

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

 

每日一笑

刚在路上看见了小学同学正在捡矿泉水瓶子,心里很不是滋味,想不到昔日的玩伴如今竟然成了竞争对手。 

WPF实现环(圆)形菜单

 

前言 

      需要实现环(圆)形菜单。

 

欢迎转发、分享、点赞,谢谢大家~。  

 

效果预览(更多效果请下载源码体验):

WPF实现环(圆)形菜单

 

一、CircularMenuItemCustomControl.cs代码如下:

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Shapes;  namespace WpfCircularMenu {      [TemplatePart(Name = RotateTransformTemplateName, Type = typeof(RotateTransform))]     public class CircularMenuItemCustomControl : Control     {         private static readonly Type _typeofSelf = typeof(CircularMenuItemCustomControl);         private const string RotateTransformTemplateName = "PART_RotateTransform";         private RotateTransform _angleRotateTransform;         public double Angle         {             get { return (double)GetValue(AngleProperty); }             set { SetValue(AngleProperty, value); }         }          public static readonly DependencyProperty AngleProperty =             DependencyProperty.Register("Angle", typeof(double), typeof(CircularMenuItemCustomControl), new UIPropertyMetadata(OnAngleChanged));          private static void OnAngleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)         {             CircularMenuItemCustomControl control = (CircularMenuItemCustomControl)d;             control.UpdateAngle();         }         void UpdateAngle()         {             if (_angleRotateTransform == null) return;             _angleRotateTransform.Angle = Angle;         }         public string MenuTxt         {             get { return (string)GetValue(MenuTxtProperty); }             set { SetValue(MenuTxtProperty, value); }         }          public static readonly DependencyProperty MenuTxtProperty =             DependencyProperty.Register("MenuTxt", typeof(string), typeof(CircularMenuItemCustomControl), new PropertyMetadata(string.Empty));            public Brush BackgroundColor         {             get { return (Brush)GetValue(BackgroundColorProperty); }             set { SetValue(BackgroundColorProperty, value); }         }         public static readonly DependencyProperty BackgroundColorProperty =            DependencyProperty.Register("BackgroundColor", typeof(Brush), typeof(CircularMenuItemCustomControl), new PropertyMetadata(null));          public ImageSource IconImage         {             get { return (ImageSource)GetValue(IconImageProperty); }             set { SetValue(IconImageProperty, value); }         }         public static readonly DependencyProperty IconImageProperty =              DependencyProperty.Register("IconImage", typeof(ImageSource), typeof(CircularMenuItemCustomControl), new PropertyMetadata(null));                 static CircularMenuItemCustomControl()         {             DefaultStyleKeyProperty.OverrideMetadata(_typeofSelf, new FrameworkPropertyMetadata(_typeofSelf));         }          public override void OnApplyTemplate()         {             base.OnApplyTemplate();             _angleRotateTransform = GetTemplateChild(RotateTransformTemplateName) as RotateTransform;             UpdateAngle();         }              } }

二、CircularMenuItemCustomControlStyle.xaml 代码如下

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"                     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"                     xmlns:local="clr-namespace:WpfCircularMenu">     <Style TargetType="{x:Type local:CircularMenuItemCustomControl}">         <Setter Property="Template">             <Setter.Value>                 <ControlTemplate TargetType="local:CircularMenuItemCustomControl">                     <Grid VerticalAlignment="Center">                         <Grid.RenderTransform>                             <RotateTransform x:Name="PART_RotateTransform" Angle="{TemplateBinding Angle}" CenterX="200" CenterY="200"></RotateTransform>                         </Grid.RenderTransform>                         <Path x:Name="PART_Path" Data="M 200,200 0,200 A 200,200 0 0 1 58.6,58.6z"                                    Fill="{TemplateBinding BackgroundColor}" VerticalAlignment="Center"/>                         <Image Source="{TemplateBinding IconImage}" RenderTransformOrigin="0.5,0.5"                                    Margin="60,70,0,0"                                     HorizontalAlignment="Left"                                     VerticalAlignment="Center"                                     Width="40" Height="40" >                             <Image.RenderTransform>                                 <RotateTransform Angle="-70"/>                             </Image.RenderTransform>                         </Image>                     </Grid>                     <ControlTemplate.Triggers>                         <Trigger Property="IsMouseOver" Value="true">                             <Setter TargetName="PART_Path" Property="Fill" Value="#009AD8"/>                             <Setter Property="Cursor" Value="Hand"/>                         </Trigger>                     </ControlTemplate.Triggers>                 </ControlTemplate>             </Setter.Value>         </Setter> </Style> </ResourceDictionary>

三、MainWindow.xaml 代码如下

<Window x:Class="WpfCircularMenu.MainWindow"         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"         xmlns:local="clr-namespace:WpfCircularMenu"         mc:Ignorable="d"         Title="MainWindow" Height="850" Width="1200"         Background="Black"         SnapsToDevicePixels="True"          TextOptions.TextFormattingMode="Display"          UseLayoutRounding="True">     <Window.Resources>         <Storyboard x:Key="CheckedStoryboard">             <DoubleAnimation Storyboard.TargetName="PART_EllipseGeometry"                              Storyboard.TargetProperty="RadiusX"                              Duration="00:00:0.4" To="200"/>             <DoubleAnimation Storyboard.TargetName="PART_EllipseGeometry"                              Storyboard.TargetProperty="RadiusY"                              Duration="00:00:0.4" To="200"/>         </Storyboard>         <Storyboard x:Key="UncheckedStoryboard">             <DoubleAnimation Storyboard.TargetName="PART_EllipseGeometry"                              Storyboard.TargetProperty="RadiusX"                              Duration="00:00:0.3" To="0"/>             <DoubleAnimation Storyboard.TargetName="PART_EllipseGeometry"                              Storyboard.TargetProperty="RadiusY"                              Duration="00:00:0.3" To="0"/>         </Storyboard>     </Window.Resources>     <Viewbox>         <Grid Height="768" Width="1024">             <Canvas>                 <ItemsControl ItemsSource="{Binding MenuArray,RelativeSource={RelativeSource AncestorType=local:MainWindow}}"                               Canvas.Left="150" Canvas.Top="150">                     <ItemsControl.Clip>                         <EllipseGeometry x:Name="PART_EllipseGeometry" RadiusX="0" RadiusY="0" Center="200,200"></EllipseGeometry>                     </ItemsControl.Clip>                     <ItemsControl.ItemTemplate>                         <DataTemplate>                             <local:CircularMenuItemCustomControl Angle="{Binding Angle}" MenuTxt="{Binding Title}"                                                                BackgroundColor="{Binding FillColor}" IconImage="{Binding IconImage}"/>                         </DataTemplate>                     </ItemsControl.ItemTemplate>                     <ItemsControl.ItemsPanel>                         <ItemsPanelTemplate>                             <Grid/>                         </ItemsPanelTemplate>                     </ItemsControl.ItemsPanel>                 </ItemsControl>                                 <ToggleButton Canvas.Left="300" Canvas.Top="300" Cursor="Hand">                     <ToggleButton.Template>                         <ControlTemplate TargetType="ToggleButton">                             <Grid>                                 <Ellipse x:Name="PART_Ellipse" Width="100" Height="100" Fill="#009AD8" ToolTip="关闭"/>                                 <Path x:Name="PART_Path" Data="M734.618 760.269c-24.013 24.013-62.925 24.013-86.886 0l-135.731-155.136-135.731 155.085c-24.013 24.013-62.925 24.013-86.886 0-24.013-24.013-24.013-62.925 0-86.886l141.21-161.28-141.261-161.382c-24.013-24.013-24.013-62.874 0-86.886s62.874-24.013 86.886 0l135.782 155.187 135.731-155.187c24.013-24.013 62.874-24.013 86.886 0s24.013 62.925 0 86.886l-141.21 161.382 141.21 161.28c24.013 24.013 24.013 62.925 0 86.938z"                                       Fill="White" Stretch="Fill" Width="20" Height="20" RenderTransformOrigin="0.5,0.5" IsHitTestVisible="False">                                 </Path>                             </Grid>                             <ControlTemplate.Triggers>                                 <Trigger Property="IsChecked" Value="false">                                     <Setter TargetName="PART_Path" Property="RenderTransform">                                         <Setter.Value>                                             <RotateTransform Angle="45"/>                                         </Setter.Value>                                     </Setter>                                     <Setter Property="ToolTip" TargetName="PART_Ellipse" Value="展开"/>                                 </Trigger>                             </ControlTemplate.Triggers>                         </ControlTemplate>                     </ToggleButton.Template>                     <ToggleButton.Triggers>                         <EventTrigger RoutedEvent="ToggleButton.Checked">                             <BeginStoryboard Storyboard="{StaticResource CheckedStoryboard}"/>                         </EventTrigger>                         <EventTrigger RoutedEvent="ToggleButton.Unchecked">                             <BeginStoryboard Storyboard="{StaticResource UncheckedStoryboard}"/>                         </EventTrigger>                     </ToggleButton.Triggers>                 </ToggleButton>                 <TextBlock Text="微信公众号:WPF开发者" FontSize="40"                            Foreground="#A9CC32" FontWeight="Bold"                            Canvas.Top="50"/>                 <Image Source="Images/gzh.png" Canvas.Left="140" Canvas.Bottom="40"/>             </Canvas>         </Grid>     </Viewbox> </Window>

 

四、MainWindow.xaml.cs 代码如下

<Window x:Class="WpfCircularMenu.MainWindow"         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"         xmlns:local="clr-namespace:WpfCircularMenu"         mc:Ignorable="d"         Title="MainWindow" Height="850" Width="1200"         Background="Black"         SnapsToDevicePixels="True"          TextOptions.TextFormattingMode="Display"          UseLayoutRounding="True">     <Window.Resources>         <Storyboard x:Key="CheckedStoryboard">             <DoubleAnimation Storyboard.TargetName="PART_EllipseGeometry"                              Storyboard.TargetProperty="RadiusX"                              Duration="00:00:0.4" To="200"/>             <DoubleAnimation Storyboard.TargetName="PART_EllipseGeometry"                              Storyboard.TargetProperty="RadiusY"                              Duration="00:00:0.4" To="200"/>         </Storyboard>         <Storyboard x:Key="UncheckedStoryboard">             <DoubleAnimation Storyboard.TargetName="PART_EllipseGeometry"                              Storyboard.TargetProperty="RadiusX"                              Duration="00:00:0.3" To="0"/>             <DoubleAnimation Storyboard.TargetName="PART_EllipseGeometry"                              Storyboard.TargetProperty="RadiusY"                              Duration="00:00:0.3" To="0"/>         </Storyboard>     </Window.Resources>     <Viewbox>         <Grid Height="768" Width="1024">             <Canvas>                 <ItemsControl ItemsSource="{Binding MenuArray,RelativeSource={RelativeSource AncestorType=local:MainWindow}}"                               Canvas.Left="150" Canvas.Top="150">                     <ItemsControl.Clip>                         <EllipseGeometry x:Name="PART_EllipseGeometry" RadiusX="0" RadiusY="0" Center="200,200"></EllipseGeometry>                     </ItemsControl.Clip>                     <ItemsControl.ItemTemplate>                         <DataTemplate>                             <local:CircularMenuItemCustomControl Angle="{Binding Angle}" MenuTxt="{Binding Title}"                                                                BackgroundColor="{Binding FillColor}" IconImage="{Binding IconImage}"/>                         </DataTemplate>                     </ItemsControl.ItemTemplate>                     <ItemsControl.ItemsPanel>                         <ItemsPanelTemplate>                             <Grid/>                         </ItemsPanelTemplate>                     </ItemsControl.ItemsPanel>                 </ItemsControl>                                 <ToggleButton Canvas.Left="300" Canvas.Top="300" Cursor="Hand">                     <ToggleButton.Template>                         <ControlTemplate TargetType="ToggleButton">                             <Grid>                                 <Ellipse x:Name="PART_Ellipse" Width="100" Height="100" Fill="#009AD8" ToolTip="关闭"/>                                 <Path x:Name="PART_Path" Data="M734.618 760.269c-24.013 24.013-62.925 24.013-86.886 0l-135.731-155.136-135.731 155.085c-24.013 24.013-62.925 24.013-86.886 0-24.013-24.013-24.013-62.925 0-86.886l141.21-161.28-141.261-161.382c-24.013-24.013-24.013-62.874 0-86.886s62.874-24.013 86.886 0l135.782 155.187 135.731-155.187c24.013-24.013 62.874-24.013 86.886 0s24.013 62.925 0 86.886l-141.21 161.382 141.21 161.28c24.013 24.013 24.013 62.925 0 86.938z"                                       Fill="White" Stretch="Fill" Width="20" Height="20" RenderTransformOrigin="0.5,0.5" IsHitTestVisible="False">                                 </Path>                             </Grid>                             <ControlTemplate.Triggers>                                 <Trigger Property="IsChecked" Value="false">                                     <Setter TargetName="PART_Path" Property="RenderTransform">                                         <Setter.Value>                                             <RotateTransform Angle="45"/>                                         </Setter.Value>                                     </Setter>                                     <Setter Property="ToolTip" TargetName="PART_Ellipse" Value="展开"/>                                 </Trigger>                             </ControlTemplate.Triggers>                         </ControlTemplate>                     </ToggleButton.Template>                     <ToggleButton.Triggers>                         <EventTrigger RoutedEvent="ToggleButton.Checked">                             <BeginStoryboard Storyboard="{StaticResource CheckedStoryboard}"/>                         </EventTrigger>                         <EventTrigger RoutedEvent="ToggleButton.Unchecked">                             <BeginStoryboard Storyboard="{StaticResource UncheckedStoryboard}"/>                         </EventTrigger>                     </ToggleButton.Triggers>                 </ToggleButton>                 <TextBlock Text="微信公众号:WPF开发者" FontSize="40"                            Foreground="#A9CC32" FontWeight="Bold"                            Canvas.Top="50"/>                 <Image Source="Images/gzh.png" Canvas.Left="140" Canvas.Bottom="40"/>             </Canvas>         </Grid>     </Viewbox> </Window>

 

更多教程欢迎关注微信公众号:

WPF实现环(圆)形菜单

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