欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

WPF实现环(圆)形菜单

程序员文章站 2022-10-27 18:01:07
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开发者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