• WPF实现环(圆)形菜单


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

    每日一笑

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

    前言 

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

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

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

    一、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开发者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

  • 相关阅读:
    N点虚拟主机管理系统(For Windows2003/2008)功能及介绍
    淘宝API开发系列商家的绑定
    在linux上使用ASP
    petshop4.0 详解之五(PetShop之业务逻辑层设计)
    vsFTPd 服务器
    中国联通短信如何 对接
    淘宝API开发系列开篇概述
    “VPS FTP应用”目录存档
    使用c#+(datagrid控件)编辑xml文件
    Centos 5.3 Nginx+php+mysql配置 独立的 Subversion (SVN)服务器
  • 原文地址:https://www.cnblogs.com/yanjinhua/p/14919516.html
Copyright © 2020-2023  润新知