当前位置:首页 > 谈天说地

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

34资源网2022-07-30325

前言 

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

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

实现代码

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

看完文章,还可以扫描下面的二维码下载快手极速版领4元红包

快手极速版二维码

快手极速版新人见面礼

除了扫码领红包之外,大家还可以在快手极速版做签到,看视频,做任务,参与抽奖,邀请好友赚钱)。

邀请两个好友奖最高196元,如下图所示:

快手极速版邀请好友奖励

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

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

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

分享给朋友:

相关文章

打败你的不一定是你的对手,有可能是一个过路人

打败你的不一定是你的对手,有可能是一个过路人

有句话叫做“羊毛出在狗身上,由猪买单”…

华梅的经典语录

华梅的经典语录

华梅,女,1951年生于天津市,祖籍无锡。现为天津师范大学美术与设计学院院长、教授、师大华梅服饰文化学研究所所长。国家人事部授衔“有突出贡献中青年专家”,享受国务院政府津贴。1997年天津市劳动模范,1998年全国教育系统巾帼建功标兵、全国…

抖音传话筒项目(傻瓜式复制粘贴轻松月入3000+)

抖音传话筒项目(傻瓜式复制粘贴轻松月入3000+)

可能你觉得你写不出优秀的文案,可能你觉得你没办法配音,可能你觉得不好意思露脸,但又想通过抖音来赚钱,那么今天给大家来说说这个抖音传话筒项目,只需要复制粘贴,一个月轻松赚到3000+,无需露脸配音,更加不需要写文案。…

应用汇下载安装最新版(2021最新版应用汇app)

应用汇下载安装最新版(2021最新版应用汇app)

Donews8月17日消息(记者 邱慧)近日,为安卓手机服务的应用型软件“应用汇”新版正式上线,同时推出“应用收藏”功能——“应用集”。 应用集主要分为“推荐”、“最热”、“最新”三类。应用汇官方介绍,此次新版上线后,安装包被优化缩小,给…

融资丨「镭昱半导体」获千万美元Pre-A轮融资,全彩Micro-LED微显示芯片助力元宇宙发展

融资丨「镭昱半导体」获千万美元Pre-A轮融资,全彩Micro-LED微显示芯片助力元宇宙发展

创业邦获悉,近日,镭昱半导体(Raysolve)宣布完成千万美元Pre-A轮融资,由高榕资本领投,耀途资本跟投,泰合资本担任独家财务顾问。至此,在短短半年内,镭昱半导体完成两轮融资,累计获得投资近亿元人民币。本轮融资将用于公司的全球首款标准…

华为小米革了康佳长虹们的命,海信怎么办?

华为小米革了康佳长虹们的命,海信怎么办?

编者按:本文来自陆玖财经,创业邦经授权发布。 电视行业真正需要面对的不是“大屏好还是小屏好”,用激光、OLED还是Mini LED之类的技术路线之争,而是一旦被视为“智能终端”,从产品形态到竞争模式的翻天覆地。 近日,海信子品牌Vidda…