【WPF】自定义下拉菜单控件DropDownButton的实现,下拉箭头旋转,ContextMenu、MenuItem的样式及FontAwesome字体图标的引用

DropDownButton控件自定义,ContextMenu、MenuItem的样式及FontAwesome字体图标的引用

效果如图,弹出收起动画等的效果还没做。

 

xaml:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:FTools.Controls">

    <Style TargetType="{x:Type local:DropDownButton}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:DropDownButton}">
                    <ControlTemplate.Resources>
                        <Storyboard x:Key="Storyboard1">
                            <DoubleAnimation Storyboard.TargetName="img" Storyboard.TargetProperty="(FrameworkElement.LayoutTransform).(RotateTransform.Angle)" 
                                                To="-180" Duration="0:0:0.2"  FillBehavior="HoldEnd" />
                        </Storyboard>
                        <Storyboard x:Key="Storyboard2">
                            <DoubleAnimation Storyboard.TargetName="img" Storyboard.TargetProperty="(FrameworkElement.LayoutTransform).(RotateTransform.Angle)" 
                                                To="0" Duration="0:0:0.2"  FillBehavior="HoldEnd" />
                        </Storyboard>
                    </ControlTemplate.Resources>
                    <Grid>
                        <Border x:Name="bd" Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            CornerRadius="5"
                            Width="{TemplateBinding Width}">
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="8*"/>
                                    <ColumnDefinition Width="2*" MinWidth="20"/>
                                </Grid.ColumnDefinitions>
                                <TextBlock Text="{Binding Text, RelativeSource={RelativeSource TemplatedParent}}"
                                       VerticalAlignment="Center"
                                       HorizontalAlignment="Center"
                                       Margin="5,0,0,0"
                                       />
                                <Path x:Name="Part_Arrow" Grid.Column="1" Data="M0,0 L4,4 8,0 Z"  VerticalAlignment="Center" HorizontalAlignment="Center"
                                      Fill="{TemplateBinding Foreground}" Margin="0,0,5,0">
                                    <Path.LayoutTransform>
                                        <RotateTransform  Angle="0"/>
                                    </Path.LayoutTransform>
                                </Path>
                            </Grid>
                        </Border>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger SourceName="bd" Property="IsMouseOver" Value="True">
                            <Setter TargetName="bd" Property="Background" Value="LightGray"/>
                        </Trigger>
                        
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!--FontAwesome字体下载及在WPF中的使用
    https://fontawesome.com/
    ##########下载
    下载地址:https://fontawesome.com/download  
    下载内容:Free For Web
    ##########使用
    双击**.ttf,进入安装页可以看到“字体名称……”,记住字体名称
    将 **.ttf复制到wpf工程自定内资源目录,FontFamily属性值=资源目录/#字体名称,如"../Resources/#Font Awesome 6 Free Solid"  
    Text的值为 FontAwesome Icon的十六进制 Unicode值,如 Text="&#xf0c5;"
    -->
    <Style x:Key="FontAwesome">
        <Setter Property="TextElement.FontFamily" Value="../Resources/#Font Awesome 6 Free Solid" />
        <Setter Property="TextBlock.Width" Value="20"></Setter>
        <Setter Property="TextBlock.Height" Value="20"></Setter>
        <Setter Property="TextBlock.TextAlignment" Value="Center"></Setter>
        <Setter Property="TextBlock.FontSize" Value="15"></Setter>
    </Style>
    <!--MenuItem样式,DropDownButton控件中嵌套ContextMenu中MenuItem引用此样式-->
    <Style x:Key="FTools.Controls.DropDownButton.MenuItemStyle" TargetType="{x:Type MenuItem}">
        <!--<Setter Property="OverridesDefaultStyle" Value="True"/>-->
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type MenuItem}">
                    <Border x:Name="mi_Border" Width="{TemplateBinding Width}" Background="Transparent" CornerRadius="5">
                        <StackPanel Orientation="Horizontal" >
                            <Border VerticalAlignment="Center" BorderBrush="{TemplateBinding Foreground }"  BorderThickness="0,0,0.5,0">
                                <TextBlock x:Name="mi_Icon" Text="{TemplateBinding Icon}" Foreground="{TemplateBinding Foreground}" Style="{DynamicResource FontAwesome}" Margin="5"/>
                            </Border>
                            <ContentPresenter 
                                Margin="5"
                                HorizontalAlignment="Left"
                                VerticalAlignment="Center"
                                ContentSource= "Header"
                                RecognizesAccessKey="True"
                                />
                        </StackPanel>   
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger SourceName="mi_Border" Property="IsMouseOver" Value="True">
                            <!--<Setter TargetName="mi_Icon"  Property="Foreground" Value="Black"/>-->
                            <Setter TargetName="mi_Border" Property="Background" Value="lightgray"/>
                        </Trigger> 
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter> 
    </Style>
    <!--ContextMenu样式,DropDownButton控件中嵌套ContextMenu引用此样式-->
    <Style x:Key="FTools.Controls.DropDownButton.ContextMenuStyle" TargetType="ContextMenu">
        <Setter Property="SnapsToDevicePixels" Value="True" />
        <Setter Property="OverridesDefaultStyle" Value="True" />
        <!--<Setter Property="Grid.IsSharedSizeScope" Value="True" />-->
        <Setter Property="HasDropShadow" Value="True" />
        <Setter Property="Foreground" Value="Black"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ContextMenu">
                    <Border Background="White" BorderBrush="DarkGray" BorderThickness="0.7" CornerRadius="5" Width="{TemplateBinding Width}">
                        <ItemsPresenter/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

C#代码:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace FTools.Controls
{
    [TemplatePart(Name = DropDownButton.part_Arrow, Type = typeof(Popup))]
    public class DropDownButton : ToggleButton
    {
        static DropDownButton()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(DropDownButton), new FrameworkPropertyMetadata(typeof(DropDownButton)));
        }
        public DropDownButton()
        {
            Binding binding = new Binding("Menu.IsOpen");
            binding.Source = this;
            this.SetBinding(IsCheckedProperty, binding);
            DataContextChanged += (sender, args) =>
            {
                if (Menu != null)
                    Menu.DataContext = DataContext;
            };
        }
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            this.path=GetTemplateChild(part_Arrow) as Path;

            if (this.path != null && this.Menu!=null)
                this.Menu.Closed += this.Menu_Closed;
            if (this.path != null && this.Menu != null)
                this.Menu.Opened += this.Menu_Opened;

        }
        public const string part_Arrow = "Part_Arrow";

        private Path path;

        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text",typeof(string), typeof(DropDownButton));
        public static readonly DependencyProperty MenuProperty = DependencyProperty.Register("Menu",
      typeof(ContextMenu), typeof(DropDownButton), new UIPropertyMetadata(null, OnMenuChanged));

        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }
        public ContextMenu Menu
        {
            get { return (ContextMenu)GetValue(MenuProperty); }
            set { SetValue(MenuProperty, value); }
        }

        private static void OnMenuChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var dropDownButton = (DropDownButton)d;
            var contextMenu = (ContextMenu)e.NewValue;
            contextMenu.DataContext = dropDownButton.DataContext;
        }

        protected override void OnClick()
        {
            if (Menu != null)
            {
                Menu.PlacementTarget = this;
                Menu.Placement = PlacementMode.Bottom;
                Menu.IsOpen = true;
                Menu.Background = new System.Windows.Media.SolidColorBrush(Color.FromRgb(255,255,255));
            }
        }

        private void Menu_Opened(object sender, EventArgs e)
        {
            RotateTransform rotateTransform = new RotateTransform();
            this.path.LayoutTransform = rotateTransform;
            DoubleAnimation ani = new DoubleAnimation();
            ani.From = 0;
            ani.To = -180;
            ani.Duration = TimeSpan.FromSeconds(0.5);
            Storyboard storyboard = new Storyboard();
            storyboard.Children.Add(ani);
            Storyboard.SetTarget(ani, this.path);
            Storyboard.SetTargetProperty(ani, new PropertyPath("(FrameworkElement.LayoutTransform).(RotateTransform.Angle)"));
            storyboard.Begin();
        }
        private void Menu_Closed(object sender, EventArgs e)
        {
            RotateTransform rotateTransform = new RotateTransform();
            this.path.LayoutTransform = rotateTransform;
            DoubleAnimation ani = new DoubleAnimation
            {
                From = -180,
                To = 0,
                Duration = TimeSpan.FromSeconds(0.5)
            };
            Storyboard storyboard = new Storyboard();
            storyboard.Children.Add(ani);
            Storyboard.SetTarget(ani, this.path);
            Storyboard.SetTargetProperty(ani, new PropertyPath("(FrameworkElement.LayoutTransform).(RotateTransform.Angle)"));
            storyboard.Begin();
        }
    }
}

 

控件的使用Xaml

                                <FControls:DropDownButton Grid.Column="6" Background="White" Foreground="{DynamicResource foregroundColor}"
                                                          FontFamily="宋体" FontSize="12"
                                                          Width="80"
                                                          Text="开始操作"
                                                          HorizontalAlignment="Right"
                                                          >
                                    <FControls:DropDownButton.Menu>
                                        <ContextMenu Style="{DynamicResource FTools.Controls.DropDownButton.ContextMenuStyle}" Width="Auto">
                                            <MenuItem Style="{DynamicResource FTools.Controls.DropDownButton.MenuItemStyle}" x:Name="miPathClean" Header="复制文件/文件夹" Icon="&#xf0c5;" Foreground="{StaticResource foregroundColor}"/>
                                            <MenuItem Style="{DynamicResource FTools.Controls.DropDownButton.MenuItemStyle}" x:Name="miPathExport" Header="移动文件/文件夹" Icon="&#xf56e;" Foreground="{StaticResource foregroundColor}"/>
                                            <MenuItem Style="{DynamicResource FTools.Controls.DropDownButton.MenuItemStyle}" x:Name="miPathInput" Header="重命名文件/文件夹" Icon="&#xf573;" Foreground="{StaticResource foregroundColor}"/>
                                        </ContextMenu>
                                    </FControls:DropDownButton.Menu>
                                </FControls:DropDownButton>

 

posted @ 2022-06-19 09:19  yzhyingcool  阅读(2681)  评论(0编辑  收藏  举报