WPF实现一个带旋转动画的菜单栏

news/2024/8/27 13:05:31/ 标签: wpf, 菜单

WPF实现一个带旋转动画的菜单

  • 一、创建WPF项目及文件
    • 1、创建项目
    • 2、创建文件夹及文件
    • 3、添加引用
  • 二、代码实现
    • 2.ControlAttachProperty类

一、创建WPF项目及文件

1、创建项目

打开VS2022,创建一个WPF项目,如下所示
在这里插入图片描述在这里插入图片描述

2、创建文件夹及文件

创建资源文件夹,添加字体图标文件,添加 Menu样式文件,如下所示
在这里插入图片描述
创建公共附加属性用控件类库,并创建对应的 ControlAttachProperty 类文件如下:
在这里插入图片描述
在这里插入图片描述

3、添加引用

右键 Menu_WPF 添加引用,将类库引用到当前项目
在这里插入图片描述

二、代码实现

2.ControlAttachProperty类

代码如下(示例):

using Microsoft.Win32;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using CheckBox = System.Windows.Controls.CheckBox;
using ComboBox = System.Windows.Controls.ComboBox;
using OpenFileDialog = Microsoft.Win32.OpenFileDialog;
using RadioButton = System.Windows.Controls.RadioButton;
using RichTextBox = System.Windows.Controls.RichTextBox;
using TextBox = System.Windows.Controls.TextBox;namespace Common.UserControl.Extession
{/// <summary>/// 公共附加属性/// </summary>public static class ControlAttachProperty{#region FocusBorderBrush 焦点边框色,输入控件public static readonly DependencyProperty FocusBorderBrushProperty = DependencyProperty.RegisterAttached("FocusBorderBrush", typeof(Brush), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null));public static void SetFocusBorderBrush(DependencyObject element, Brush value){element.SetValue(FocusBorderBrushProperty, value);}public static Brush GetFocusBorderBrush(DependencyObject element){return (Brush)element.GetValue(FocusBorderBrushProperty);}#endregion#region MouseOverBorderBrush 鼠标进入边框色,输入控件public static readonly DependencyProperty MouseOverBorderBrushProperty =DependencyProperty.RegisterAttached("MouseOverBorderBrush", typeof(Brush), typeof(ControlAttachProperty),new FrameworkPropertyMetadata(Brushes.Transparent,FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits));/// <summary>/// Sets the brush used to draw the mouse over brush./// </summary>public static void SetMouseOverBorderBrush(DependencyObject obj, Brush value){obj.SetValue(MouseOverBorderBrushProperty, value);}/// <summary>/// Gets the brush used to draw the mouse over brush./// </summary>[AttachedPropertyBrowsableForType(typeof(TextBox))][AttachedPropertyBrowsableForType(typeof(CheckBox))][AttachedPropertyBrowsableForType(typeof(RadioButton))][AttachedPropertyBrowsableForType(typeof(DatePicker))][AttachedPropertyBrowsableForType(typeof(ComboBox))][AttachedPropertyBrowsableForType(typeof(RichTextBox))]public static Brush GetMouseOverBorderBrush(DependencyObject obj){return (Brush)obj.GetValue(MouseOverBorderBrushProperty);}#endregion#region AttachContentProperty 附加组件模板/// <summary>/// 附加组件模板/// </summary>public static readonly DependencyProperty AttachContentProperty = DependencyProperty.RegisterAttached("AttachContent", typeof(ControlTemplate), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null));public static ControlTemplate GetAttachContent(DependencyObject d){return (ControlTemplate)d.GetValue(AttachContentProperty);}public static void SetAttachContent(DependencyObject obj, ControlTemplate value){obj.SetValue(AttachContentProperty, value);}#endregion#region WatermarkProperty 水印/// <summary>/// 水印/// </summary>public static readonly DependencyProperty WatermarkProperty = DependencyProperty.RegisterAttached("Watermark", typeof(string), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(""));public static string GetWatermark(DependencyObject d){return (string)d.GetValue(WatermarkProperty);}public static void SetWatermark(DependencyObject obj, string value){obj.SetValue(WatermarkProperty, value);}#endregion#region FIconProperty 字体图标/// <summary>/// 字体图标/// </summary>public static readonly DependencyProperty FIconProperty = DependencyProperty.RegisterAttached("FIcon", typeof(string), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(""));public static string GetFIcon(DependencyObject d){return (string)d.GetValue(FIconProperty);}public static void SetFIcon(DependencyObject obj, string value){obj.SetValue(FIconProperty, value);}#endregion#region FIconSizeProperty 字体图标大小/// <summary>/// 字体图标/// </summary>public static readonly DependencyProperty FIconSizeProperty = DependencyProperty.RegisterAttached("FIconSize", typeof(double), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(12D));public static double GetFIconSize(DependencyObject d){return (double)d.GetValue(FIconSizeProperty);}public static void SetFIconSize(DependencyObject obj, double value){obj.SetValue(FIconSizeProperty, value);}#endregion#region FIconMarginProperty 字体图标边距/// <summary>/// 字体图标/// </summary>public static readonly DependencyProperty FIconMarginProperty = DependencyProperty.RegisterAttached("FIconMargin", typeof(Thickness), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null));public static Thickness GetFIconMargin(DependencyObject d){return (Thickness)d.GetValue(FIconMarginProperty);}public static void SetFIconMargin(DependencyObject obj, Thickness value){obj.SetValue(FIconMarginProperty, value);}#endregion#region AllowsAnimationProperty 启用旋转动画/// <summary>/// 启用旋转动画/// </summary>public static readonly DependencyProperty AllowsAnimationProperty = DependencyProperty.RegisterAttached("AllowsAnimation", typeof(bool), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(false, AllowsAnimationChanged));public static bool GetAllowsAnimation(DependencyObject d){return (bool)d.GetValue(AllowsAnimationProperty);}public static void SetAllowsAnimation(DependencyObject obj, bool value){obj.SetValue(AllowsAnimationProperty, value);}/// <summary>/// 旋转动画刻度/// </summary>private static DoubleAnimation RotateAnimation = new DoubleAnimation(0, new Duration(TimeSpan.FromMilliseconds(200)));/// <summary>/// 绑定动画事件/// </summary>private static void AllowsAnimationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){var uc = d as FrameworkElement;if (uc == null) return;if (uc.RenderTransformOrigin == new Point(0, 0)){uc.RenderTransformOrigin = new Point(0.5, 0.5);RotateTransform trans = new RotateTransform(0);uc.RenderTransform = trans;}var value = (bool)e.NewValue;if (value){RotateAnimation.To = 180;uc.RenderTransform.BeginAnimation(RotateTransform.AngleProperty, RotateAnimation);}else{RotateAnimation.To = 0;uc.RenderTransform.BeginAnimation(RotateTransform.AngleProperty, RotateAnimation);}}#endregion#region CornerRadiusProperty Border圆角/// <summary>/// Border圆角/// </summary>public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.RegisterAttached("CornerRadius", typeof(CornerRadius), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null));public static CornerRadius GetCornerRadius(DependencyObject d){return (CornerRadius)d.GetValue(CornerRadiusProperty);}public static void SetCornerRadius(DependencyObject obj, CornerRadius value){obj.SetValue(CornerRadiusProperty, value);}#endregion#region LabelProperty TextBox的头部Label/// <summary>/// TextBox的头部Label/// </summary>public static readonly DependencyProperty LabelProperty = DependencyProperty.RegisterAttached("Label", typeof(string), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null));[AttachedPropertyBrowsableForType(typeof(TextBox))]public static string GetLabel(DependencyObject d){return (string)d.GetValue(LabelProperty);}public static void SetLabel(DependencyObject obj, string value){obj.SetValue(LabelProperty, value);}#endregion#region LabelTemplateProperty TextBox的头部Label模板/// <summary>/// TextBox的头部Label模板/// </summary>public static readonly DependencyProperty LabelTemplateProperty = DependencyProperty.RegisterAttached("LabelTemplate", typeof(ControlTemplate), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(null));[AttachedPropertyBrowsableForType(typeof(TextBox))]public static ControlTemplate GetLabelTemplate(DependencyObject d){return (ControlTemplate)d.GetValue(LabelTemplateProperty);}public static void SetLabelTemplate(DependencyObject obj, ControlTemplate value){obj.SetValue(LabelTemplateProperty, value);}#endregion}
}

Menu样式文件实现

    <!--背景透明的HeaderItem样式,带旋转动画--><Style x:Key="TransparentHeaderMenuItem" TargetType="{x:Type MenuItem}"><Setter Property="BorderBrush" Value="{StaticResource MenuBorderBrush}"/><Setter Property="BorderThickness" Value="1"/><Setter Property="Background" Value="{StaticResource MenuBackground}"/><Setter Property="Foreground" Value="{StaticResource TextForeground}"/><Setter Property="FontSize" Value="{StaticResource FontSize}"/><Setter Property="Margin" Value="2,0,2,0"/><Setter Property="Height" Value="30"/><Setter Property="local:ControlAttachProperty.FIconSize" Value="18"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type MenuItem}"><Grid x:Name="Bg" VerticalAlignment="{TemplateBinding VerticalAlignment}"><StackPanel Orientation="Horizontal" x:Name="border" VerticalAlignment="Center" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"><!--icon--><TextBlock x:Name="PART_Icon" Text="{TemplateBinding Icon}" Foreground="{TemplateBinding Foreground}" local:ControlAttachProperty.AllowsAnimation="{Binding IsSubmenuOpen,RelativeSource={RelativeSource TemplatedParent}}"FontSize="{TemplateBinding local:ControlAttachProperty.FIconSize}" Style="{StaticResource FIcon}" /><TextBlock x:Name="txtHeader" Margin="5 0 0 0" FontSize="{TemplateBinding FontSize}" HorizontalAlignment="Stretch" Text="{TemplateBinding Header}" VerticalAlignment="Center" Grid.Column="1" Foreground="{TemplateBinding Foreground}"/></StackPanel><!--弹出子集菜单容器--><Popup x:Name="SubMenuPopup" AllowsTransparency="true" IsOpen="{Binding IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}" Placement="Bottom"  Focusable="false" VerticalOffset="0"PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}"><Border Background="{TemplateBinding Background}"  CornerRadius="0" Margin="5" Effect="{StaticResource DefaultDropShadow}"BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"><Grid x:Name="SubMenu" Grid.IsSharedSizeScope="True"><StackPanel Margin="10" IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Cycle"/></Grid></Border></Popup></Grid><!--触发器--><ControlTemplate.Triggers><!--高亮状态--><Trigger Property="IsHighlighted" Value="true"><Setter Property="Foreground" Value="{StaticResource MouseOverForeground}"></Setter></Trigger><Trigger Property="IsPressed" Value="true"><Setter Property="Foreground" Value="{StaticResource PressedForeground}"></Setter></Trigger><Trigger Property="IsEnabled" Value="False"><Setter TargetName="border" Value="{StaticResource DisableOpacity}" Property="Opacity"></Setter></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></Style>

MainWindow样式实现

  <Menu Width="80" Height="30" Margin="3" Background="Transparent" ><MenuItem Header="展开菜单" Style="{StaticResource TransparentHeaderMenuItem}" Padding="0" Icon="&#xe61b;" ><MenuItem Style="{StaticResource TransparentHeaderMenuItem}" Icon="&#xe605;" Header="设置" /><MenuItem Style="{StaticResource TransparentHeaderMenuItem}" Icon="&#xe656;" Header="插件管理" /><MenuItem Style="{StaticResource TransparentHeaderMenuItem}" Icon="&#xe65e;"  Header="用户管理" /><MenuItem Style="{StaticResource TransparentHeaderMenuItem}" Icon="&#xe659;" Header="修改密码" /><MenuItem Style="{StaticResource TransparentHeaderMenuItem}" Icon="&#xe7c6;" Header="在线更新" /><Separator Background="SpringGreen" Style="{StaticResource HorizontalSeparatorStyle}"/><MenuItem Style="{StaticResource TransparentHeaderMenuItem}" Icon="&#xe6d5;" Header="问题反馈" /><MenuItem Style="{StaticResource TransparentHeaderMenuItem}" Icon="&#xe65f;" Header="技术支持" /><MenuItem Style="{StaticResource TransparentHeaderMenuItem}" Icon="&#xe600;" Header="帮助" /><MenuItem Style="{StaticResource TransparentHeaderMenuItem}" Icon="&#xe622;" Header="关于" /></MenuItem></Menu>

http://www.ppmy.cn/news/1475803.html

相关文章

小程序创建与项目初始化(构建 npm + 集成 Sass)

一、打开微信开发者工具 确认 左侧导航栏是否选中的 小程序点击 【】创建小程序 二、创建小程序 三、初始化 清空 app.wxss、app.js 去掉 rendererOptions 和 componentFramework 不需要最新的搜索引擎 留下以下文件 四、自定义构建 npm 集成 Sass 首先 先把小程序源…

JMeter进行HTTP接口测试的技术要点

参数化 用户定义的变量 用的时候 ${名字} 用户参数 在参数列表中传递 并且也是${} csv数据文件设置 false 不忽略首行 要首行 从第一行读取 true 忽略首行 从第二行开始 请求时的参数设置&#xff1a; 这里的名称是看其接口需要的请求参数的名称 这里的变量名称就是为csv里面…

QLoRa使用教程

一、定义 定义案例1 二、实现 定义 QLoRa: 量化LoRa. 网址&#xff1a;https://huggingface.co/docs/peft/main/en/developer_guides/quantization案例1 1. 4bit 量化LoRa import torch from transformers import BitsAndBytesConfigconfig BitsAndBytesConfig(load_in_4b…

各地户外分散视频监控点位,如何实现远程集中实时监看?

公司业务涉及视频监控项目承包搭建&#xff0c;此前某个项目需求是为某林业公司提供视频监控解决方案&#xff0c;需要实现各地视频摄像头的集中实时监看&#xff0c;以防止国家储备林的盗砍、盗伐行为。 公司原计划采用运营商专线连接各个视频监控点位&#xff0c;实现远程视…

计算机图形学入门28:相机、透镜和光场

1.前言 相机(Cameras)、透镜(Lenses)和光场(Light Fields)都是图形学中重要的组成部分。在之前的学习中&#xff0c;都是默认它们的存在&#xff0c;所以现在也需要单独拿出来学习下。 2.成像方法 计算机图形学有两种成像方法&#xff0c;即合成(Synthesis)和捕捉(Capture)。前…

HBase 在统一内容平台业务的优化实践

作者&#xff1a;来自 vivo 互联网服务器团队-Leng Jianyu、Huang Haitao HBase是一款开源高可靠性、扩展性、高性能和灵活性的分布式非关系型数据库&#xff0c;本文围绕数据库选型以及使用HBase的痛点展开&#xff0c;从四个方面对HBase的使用进行优化&#xff0c;取得了一些…

使用Redis实现签到功能:Java示例解析

使用Redis实现签到功能&#xff1a;Java示例解析 在本博客中&#xff0c;我们将讨论一个使用Redis实现的签到功能的Java示例。该示例包括两个主要方法&#xff1a;sign()和signCount()&#xff0c;分别用于用户签到和计算用户当月的签到次数。 1. 签到方法&#xff1a;sign()…

3d为什么删掉模型不能返回?---模大狮模型网

在展览3D模型设计行业中&#xff0c;设计师们经常面临一个关键问题&#xff1a;一旦删除了模型的某些部分&#xff0c;为什么很难或者无法恢复原始状态?这不仅是技术上的挑战&#xff0c;更是设计过程中需要深思熟虑的重要考量。本文将探讨这一问题的原因及其在实际工作中的影…

【图解大数据技术】Spark

【图解大数据技术】Spark Spark简介RDDSpark示例Spark运行原理整体流程DAG 与 stage 为什么Spark比MapReduce快&#xff1f; Spark简介 Spark与MapReduce一样&#xff0c;也是大数据计算框架。Spark相比MapReduce拥有更快的执行速度和更低的编程复杂度。 Spark包括以下几个模…

AI算法17-贝叶斯岭回归算法Bayesian Ridge Regression | BRR

贝叶斯岭回归算法简介 贝叶斯岭回归&#xff08;Bayesian Ridge Regression&#xff09;是一种回归分析方法&#xff0c;它结合了岭回归&#xff08;Ridge Regression&#xff09;的正则化特性和贝叶斯统计的推断能力。这种方法在处理具有大量特征的数据集时特别有用&#xff…

搜索引擎中的相关性模型

一、什么是相关性模型&#xff1f; 相关性模型主要关注的是query和doc的相关性。例如给定query&#xff0c;和1000个doc&#xff0c;找到哪个doc是好query最相关的。 二、为什么需要相关性模型&#xff1f; 熟悉es的应该都熟悉BM25相关性算法。它是一个很简单的相关性算法。我…

Hadoop-28 ZooKeeper集群 ZNode简介概念和测试 数据结构与监听机制 持久性节点 持久顺序节点 事务ID Watcher机制

章节内容 上节我们完成了&#xff1a; ZooKeeper 集群配置ZooKeeper 集群启动ZooKeeper 集群状况查看Follower 和 Leader 节点 背景介绍 这里是三台公网云服务器&#xff0c;每台 2C4G&#xff0c;搭建一个Hadoop的学习环境&#xff0c;供我学习。 之前已经在 VM 虚拟机上搭…

jenkins系列-06.harbor

https://github.com/goharbor/harbor/releases?page2 https://github.com/goharbor/harbor/releases/download/v2.3.4/harbor-offline-installer-v2.3.4.tgz harbor官网&#xff1a;https://goharbor.io/ 点击 Download now 链接&#xff0c;会自动跳转到上述github页面&am…

多旋翼+VR眼镜:10寸FPV穿越机技术详解

FPV&#xff08;First Person View&#xff09;穿越机&#xff0c;是指通过第一人称视角来驾驶的无人机&#xff0c;特别强调速度和灵活性&#xff0c;常常用于竞赛、航拍和探索等领域。结合多旋翼设计和VR眼镜&#xff0c;FPV穿越机为用户提供了身临其境的飞行体验。 多旋翼技…

Android人脸解锁源码解析

1 人脸解锁相关类介绍 FaceManager FaceManager是一个私有接口&#xff0c;用于维护FaceService的之间连接。Keyguard通过该接口访问具有自定义界面的人脸识别身份验证硬件。应用无权访问FaceManager&#xff0c;必须改为使用BiometricPrompt。 FaceService 该框架实现用于管…

vscode连接到WSL子系统报错/bin/ea1445cc7016315d0f5728f8e8b12a45dc0a7286/node: not found

子系统单独启动没有问题&#xff0c;vscode启动wsl子系统报错 报错如下&#xff1a; /home/sophia/.vscode-server/bin/ea1445cc7016315d0f5728f8e8b12a45dc0a7286/bin/code-server: 12: /home/sophia/.vscode-server/bin/ea1445cc7016315d0f5728f8e8b12a45dc0a7286/node: n…

git github gitee 三者关系

Git&#xff1a; Git 是一个分布式版本控制系统&#xff0c;用于跟踪源代码的更改。它由 Linus Torvalds 于 2005 年开发&#xff0c;目的是更好地管理 Linux 内核开发。Git 是一个命令行工具&#xff0c;具有以下特点&#xff1a; 分布式&#xff1a;每个开发者的工作目录都是…

B树:深入解析与实战应用

在数据结构和算法的世界中&#xff0c;B树&#xff08;B-tree&#xff09;无疑是一颗璀璨的明星。它不仅广泛应用于数据库和文件系统的索引结构中&#xff0c;而且在许多需要高效数据检索的场景中发挥着重要作用。本文将从B树的基本概念入手&#xff0c;通过图文结合的方式&…

海外媒体宣发:尼日利亚媒体通稿报道发布-大舍传媒

尼日利亚媒体概述 尼日利亚&#xff0c;作为非洲人口最多的国家&#xff0c;拥有多元化的媒体环境。在这个国家&#xff0c;你可以找到各种类型的媒体&#xff0c;包括传统媒体和新媒体。传统媒体主要包括报纸、电视和广播&#xff0c;而新媒体则主要是互联网和社交媒体。 尼…

Java+springboot+vue智慧班牌小程序源码,智慧班牌系统可以提供哪些服务?

智慧班牌全套源码&#xff0c;系统技术架构&#xff1a;Javaspringbootvue element-ui小程序电子班牌&#xff1a;Java Android演示正版授权。 智慧班牌在智慧校园的数字化建设中提供了多种服务&#xff0c;这些服务不仅丰富了校园的信息展示方式&#xff0c;还促进了家校互动…