当前位置:首页 > 谈天说地 > 正文内容

WPF实现环(圆)形菜单的示例代码

34资源网2022年07月30日 10:57220

前言 

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

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

实现代码

1.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();
        }
       

    }
}

2.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>

3.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>

4.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菜单内容请搜索萬仟网以前的文章或继续浏览下面的相关文章希望大家以后多多支持萬仟网!

看完文章,还可以用支付宝扫描下面的二维码领取一个支付宝红包,目前可领1-88元不等

支付宝红包二维码

除了扫码可以领取之外,大家还可以(复制 720087999 打开✔支付宝✔去搜索, h`o`n.g.包哪里来,动动手指就能领)。

看下图所示是好多参与这次活动领取红包的朋友:

支付宝红包

扫描二维码推送至手机访问。

版权声明:本文由34楼发布,如需转载请注明出处。

本文链接:https://www.34l.com/post/20050.html

分享给朋友:

相关文章

最傻的六种员工离职理由,希望你不是其中一员
最傻的六种员工离职理由,希望你不是其中一员

春节后,今年的中国员工离职率应该是最低的。但是职场上,还是会有很多员工提离职。离职原因各种各样, 不开心,不舒服,工资少,学不到东西等等。那么,最傻的六种员工离职是哪些呢?一、新领导到来有些员工习惯了以前的领导的工作方式,怕自己不适应新领导...

打不死的小强励志语句,关于小强的7个句子分享
打不死的小强励志语句,关于小强的7个句子分享

1、野火烧不尽,春风吹又生用打不死的小强来形容,真的是再合适不过了2、命中注定无法改变,总觉得自己是打不死的小强,这下终于生病了,最对不起的就是自己了3、好好干吧!要成为一名打不死的小强。无论别人怎样,你都要成为那个开心,优秀的自己,好吗?...

抖音黄v认证有什么好处(抖音流量高的是蓝v和黄v)
抖音黄v认证有什么好处(抖音流量高的是蓝v和黄v)

我将要在这里告诉你们关于抖音号橱窗蓝v抖音小店所有的知识,认真看完。我们一个抖音号需要一个手机卡,那么一个人可以去移动、联通、电信各办五张,一共是15张手机卡,也就是说一个人可以拥有15个抖音号;那么一个人一张身份证只可以实名一个抖音号,实...

微信直接打开淘宝抖音,但李佳琦罗永浩带货,买不了
微信直接打开淘宝抖音,但李佳琦罗永浩带货,买不了

图源:摄图网 编者按:本文来自微信公众号IT时报(ID:vittimes),作者:江丽雯,编辑:郝俊慧 挨踢妹,排版:季嘉颖,创业邦经授权转载 11月29日,微信放开了对外链的限制。 当日发布的《关于〈微信外部链接内容管理规范〉的更新声明...

如何删掉分页符空白页(空白页的解决方法)
如何删掉分页符空白页(空白页的解决方法)

我相信大家在编辑Word文档时,一定都遇到过这种恼人的情况,好不容易编辑完文档了,却发现末尾留下了空白页,想删除都无从下手。那么到底如何快速删除Word空白页呢?今天就来教大家几招,保证让你删得干干净净! 方法一:Shift键删除空白...

打代码赚钱的平台(免费打码赚钱软件)
打代码赚钱的平台(免费打码赚钱软件)

前言 开源项目作者:JackonYang 今天推荐的这个项目是「list-of-wechat-mini-program-list」,开源微信小程序列表的列表、有赚钱能力的小程序开源代码。 这个项目分为两部分,第一部分是开源微信小程序列...