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

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

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

前言 

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

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

实现代码

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

分享给朋友:

相关文章

木村久一:所谓天才人物指的就是具有毅力的人、勤奋的人、入迷的人和忘我的人
木村久一:所谓天才人物指的就是具有毅力的人、勤奋的人、入迷的人和忘我的人

木村久一:所谓天才人物指的就是具有毅力的人、勤奋的人、入迷的人和忘我的人。...

年轻人不讲武德和耗子尾汁什么意思?什么梗?
年轻人不讲武德和耗子尾汁什么意思?什么梗?

最近经常在朋友圈,抖音上面刷到一些视频评论说年轻人不讲5的和耗子尾汁,小编看着感觉好奇怪,刚开始有点懵逼,结果去网上查了一下才知道,这是太极大师马保国老师讲的。究竟这个梗是怎么来的呢?其实,刚开始人家只是取笑这个马保国大师的梗,后面没有想到...

30句用喜从天降造句的语句
30句用喜从天降造句的语句

1、让他去泰山旅游,那真是喜从天降。2、霜降日,天将降大福于你:福从天降,好运排山倒海;喜从天降,好事缠缠绵绵;财从天降,收获盆满钵满;乐从天降,快乐从不间断!3、霜降霜降,鸿运当头,喜从天降。寿星降,健康长寿身体棒。财神降,财运亨通路路畅...

泰戈尔的名言名句:世界上最远的距离
泰戈尔的名言名句:世界上最远的距离

世界上最远的距离不是生与死的距离而是我站在你的面前你却不知道我爱你世界上最远的距离不是我站在你的面前你却不知道我爱你而是爱到痴迷却不能说我爱你世界上最远的距离不是我不能说我爱你而是想你痛彻心脾却只能深埋心底世界上最远的距离不是我不能说我想你...

想要赚钱创业首先要改变自己的思维
想要赚钱创业首先要改变自己的思维

大市场,前景行业,无非是能源、通信、金融行业。小市场,比较有前景的,是大众所需,消费忠识度比较高的行业,比如饮食,零售、生产。无论是工作,还是创业!你需要选择自己兴趣,找准自己的优势,发现你的特长.1:考虑你的兴趣,做你最喜欢做的,只有让工...

联想新手机什么时候上市(联想2021即将上市新款笔记本)
联想新手机什么时候上市(联想2021即将上市新款笔记本)

11月8日,联想中国区手机业务部总经理发布了一则新机预告:摩托罗拉edge X的发布已进入倒计时阶段,在骁龙898处理器即将发布之际预告新机,很大可能预示着首发权已到手。而在双十一当天,陈劲又发布了一则微博,暗示摩托罗拉的全新手机已到手,“...