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

目录
  • 前言
  • 实现代码
    • 1.CircularMenuItemCustomControl.cs
    • 2.CircularMenuItemCustomControlStyle.xaml
    • 3.MainWindow.xaml
    • 4.MainWindow.xaml.cs

前言

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

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

实现代码

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

(0)

相关推荐

  • WPF弹出右键菜单时判断鼠标是否选中该项

    和上篇在WPF的TreeView中实现右键选定一样,这仍然是一个右键菜单的问题: 这个需求是在一个实现剪贴板的功能的时候遇到的:在弹出右键菜单时,如果菜单弹出位置在ListViewItem中时,我们认为这项已经被选中,可以使用剪贴板功能. 当菜单弹出位置在ListView的空白处时,我们一般认为没有项被选中,此时是不应该使能剪贴板功能的. 但是这个时候,该项仍然是选中的.不能通过Item的IsSelected的属性来区分这两种情况.这样,就需要我们加一个判断鼠标是否在所选的节点上的函数.实现这个

  • C#对WPF数据绑定的菜单插入分隔Seperator

    WPF代码展示 <Window.Resources> <local:Source x:Key="src"/> </Window.Resources> <StackPanel> <Menu> <MenuItem Header="Animals" ItemsSource="{Binding Source={StaticResource src}}" /> </Menu>

  • WPF实现雷达图(仿英雄联盟)的示例代码

    目录 前言 实现代码 效果预览 前言 有小伙伴提出需要实现雷达图. 由于在WPF中没有现成的雷达图控件,所以我们自己实现一个. PS:有更好的方式欢迎推荐. 实现代码 一.创建 RadarChart.cs 菜单继承 Control代码如下 RadarChart.cs实现思路如下 1.RadarArray :存放展示集合 . 2.重写OnRender . 3.根据三角函数和圆的半径计算出圆上的N个点绘制成多边形GetPolygonPoint(). 4.在绘制多边形的时候因为需要多个大小不一的多边形

  • WPF仿LiveCharts实现饼图的绘制

    目录 前言 一.PieControl.cs 二.App.xaml 三.MainWindow.xaml 四.MainWindow.xaml.cs 每日一笑 下班和实习生一起回家,公交站等车,一乞丐把碗推向实习生乞讨.这时,实习生不慌不忙的说了句:“我不要你的钱,你这钱来的也不容易.” 前言 有小伙伴需要统计图. 效果预览(更多效果请下载源码体验) 一.PieControl.cs using System.Collections.ObjectModel; using System.Windows;

  • WPF实现绘制统计图(柱状图)的方法详解

    目录 前言 实现代码 效果预览 前言 有小伙伴提出需要实现统计图. 由于在WPF中没有现成的统计图控件,所以我们自己实现一个. PS:有更好的方式欢迎推荐. 实现代码 一.创建 BasicBarChart.cs 继承 Control代码如下. BasicBarChart.cs实现思路如下 1.SeriesArray :存放展示集合 . 2.重写OnRender . 3.先绘制X轴线. 4.调用GetFormattedText()绘制底部类别. 5.调用GetFormattedText()绘制左侧

  • WPF实现半圆形导航菜单

    本文实例为大家分享了WPF实现半圆形导航菜单的具体代码,供大家参考,具体内容如下 实现效果如下: 思路: 扇形自定义控件组合成半圆型菜单,再通过clip实现菜单的展开和折叠. 步骤: 1.扇形自定义控件CircularSectorControl 窗体布局xaml: <Grid x:Name="mainGrid" MouseEnter="MainGrid_MouseEnter" MouseLeave="MainGrid_MouseLeave"

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

    目录 前言 实现代码 1.CircularMenuItemCustomControl.cs 2.CircularMenuItemCustomControlStyle.xaml 3.MainWindow.xaml 4.MainWindow.xaml.cs 前言 需要实现环(圆)形菜单. 效果预览(更多效果请下载源码体验): 实现代码 1.CircularMenuItemCustomControl.cs using System; using System.Collections.Generic;

  • WPF模拟实现Gitee泡泡菜单的示例代码

    WPF实现 Gitee泡泡菜单 框架使用大于等于.NET40: Visual Studio 2022; 项目使用 MIT 开源许可协议: 需要实现泡泡菜单需要使用Canvas画布进行添加内容: 保证颜色随机,位置不重叠: 点击泡泡获得当前泡泡的值: 实现代码 1) BubblleCanvas.cs 代码如下: using System.Windows; using System.Windows.Controls; using WPFDevelopers.Helpers; using WPFDev

  • 使用DrawerLayout完成滑动菜单的示例代码

    用Toolbar编写自定义导航栏,在AndroidManifest.xml中你要编滑动菜单的界面处加入如下代码 <activity android:name=".DrawerLayoutActivity" android:theme="@style/NoTitle"></activity> 在values下的styles.xml中加入 <style name="NoTitle" parent="Theme.

  • WPF实现好看的Loading动画的示例代码

    实现思路 框架使用大于等于.NET40: Visual Studio 2022; 项目使用 MIT 开源许可协议: 老板觉得公司系统等待动画转圈太简单,所以需要做一个稍微好看点的,就有这篇等待RingLoading动画 最外层使用Viewbox为父控件内部嵌套创建三组 Grid -> Ellipse . Border分别给它们指定不同的Angle从左侧开始 -135 225 54,做永久 Angle 动画: PART_Ring1.RotateTransform.Angle从From -135 到

  • PyQt5中QTableWidget如何弹出菜单的示例代码

    QTableWidget是Qt程序中常用的显示数据表格的控件,类似于c#中的DataGrid.QTableWidget是QTableView的子类,它使用标准的数据模型,并且其单元数据是通过QTableWidgetItem对象来实现的,使用QTableWidget时就需要QTableWidgetItem.用来表示表格中的一个单元格,整个表格就是用各个单元格构建起来的 在PyQt5中,常需要对表格进行右击后弹出菜单,要实现这个操作就是两个问题:1. 如何弹出菜单.2. 如何在满足条件的情况下弹出菜

  • JavaScript中layim之整合右键菜单的示例代码

    一. 效果演示 1.1.好友右键菜单: 1.2.分组右键菜单: 1.3.群组右键菜单: 二. 实现教程 接下来我们以好友右键菜单为例,实现步骤如下: 2.1.绑定好友右击事件: /* 绑定好友右击事件 */ $('body').on('mousedown', '.layim-list-friend li ul li', function(e){ // 过滤非右击事件 if(3 != e.which) { return; } // 不再派发事件 e.stopPropagation(); var o

  • SpringBoot mybatis 实现多级树形菜单的示例代码

    一.前言 iview-admin中提供了 v-org-tree这么一个vue组件可以实现树形菜单,下面小编来提供一下在element-ui中的使用教程(项目见:https://github.com/lison16/v-org-tree) 小编集成了el-dropdown下拉菜单(鼠标左击显示菜单),和右击自定义菜单,两种方式,效果图如下: 二.使用教程 (1)安装依赖 npm install clipboard npm install v-click-outside-x npm install

  • OpenCV绘制圆端矩形的示例代码

    目录 功能函数 测试代码 测试效果 本文主要介绍了OpenCV绘制圆端矩形的示例代码,分享给大家,具体如下: 功能函数 // 绘制圆端矩形(药丸状,pill) void DrawPill(cv::Mat mask, const cv::RotatedRect &rotatedrect, const cv::Scalar &color, int thickness, int lineType) { cv::Mat canvas = cv::Mat::zeros(mask.size(), CV

  • vue-router 基于后端permissions动态生成导航菜单的示例代码

    目录 Vue.js 1.注册全局守卫 2.Vuex状态管理 全局缓存routes 3.路由拦截 4.路由菜单 5.递归菜单vue组件 Vue.js vue-router vuex 1.注册全局守卫 核心逻辑 1.token身份验证(后端) => token失效返回登录页面 2.获取用户权限 3.校验permissions,动态添加路由菜单 router.beforeResolve 注册一个全局守卫.和 router.beforeEach 类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路

  • vue+elementui+vuex+sessionStorage实现历史标签菜单的示例代码

    一般是有左侧菜单后,然后要在页面上部分添加历史标签菜单需求. 借鉴其他项目,以及网上功能加以组合调整实现 按照标签实现方式步骤来(大致思路): 1,写一个tagNav标签组件 2,在路由文件上每个路由组件都添加meta属性 meta:{title:'组件中文名'} 3,在store的mutation.js文件中写标签的添加/删除方法以及在方法中更新sessionStorage数据 4,在主页面上添加组件以及router-view外层添加keep-alive组件,我这边是main.vue为登录后主

随机推荐