一、创建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>

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部