WPF自定义控件01:FlatButton

举报
jackwangcumt 发表于 2021/08/21 19:12:49 2021/08/21
【摘要】 主要介绍一下WPF如何实现自定义控件,通过继承Button控件,和自定义样式来实现Flat样式的漂亮Button。虽然这个FlatButton也可以通过内置的样式达到同样的效果,但自定义控件可以更好的封装和重用,使用起来更加的方便。

1 WPF概述


     根据百度百科,WPF是Windows Presentation Foundation的缩写,它是微软推出的基于Windows 的新一代UI框架,属于.NET Framework 3.0+的一部分。WPF提供了统一的编程模型、语言和框架,真正做到了UI与逻辑的分离,同时也提供了全新的多媒体交互用户图形界面。借助WPF,可以让开发人员开发出绚丽的应用程序。

     环境准备:Visual Studio 2019社区版(免费);.NET FrameWork 5 。

2 WPF项目创建


     首先需要利用Visual Studio 2019社区版创建一个新的WPF桌面应用WpfControls和一个新的WPF控件库项目Yd.WpfControls。并在WpfControls项目中添加对Yd.WpfControls项目的引用。具体如下所示

1.jpg

此项目中,已经创建了一些文件,下面将分重点进行说明。

3 自定义控件FlatButton


第一步,定义一些基础的类,其中有字体的设置FlatFonts.cs,其代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;

namespace Yd.WpfControls
{
    public class FlatFonts
    {
        public static FontFamily contentFontFamily = new FontFamily("Microsoft YaHei");
    
        public static double contentFontSize = 16D;
    }
}

其中就是定义了一个默认的字体和字号,注意字号是double类型的。同样的,下面给出颜色的定义,FlatColors.cs示例代码如下:

using System;
using System.Collections.Generic;
using System.Windows.Media;
namespace Yd.WpfControls
{
    public class FlatColors
    {
        //https://flatuicolors.com/palette/defo
        public static Brush TUROUOISE = new SolidColorBrush( Color.FromRgb(26, 188, 156));
        public static Brush EMERALD = new SolidColorBrush(Color.FromRgb(46, 204, 113));
        public static Brush PETER_RIVER = new SolidColorBrush(Color.FromRgb(52, 152, 219));
        public static Brush BELIZE_HOLE = new SolidColorBrush(Color.FromRgb(41, 128, 185));
        public static Brush MIDNIGHT_BLUE = new SolidColorBrush(Color.FromRgb(44, 62, 80));
        public static Brush CLOUDS = new SolidColorBrush(Color.FromRgb(236, 240, 241));
    }
}

注意:颜色是来自Flat UI Color系列的网站,且颜色定义的类型的Brush,而不是Color。下面再给出FlatButton的Type定义,FlatButtonType.cs示例代码如下:

namespace Yd.WpfControls
{
    public enum FlatButtonType
    {
        Default,
        Warn,
        Danger
    }
}

第二步,创建一个自定义控件,他会自动创建一个样式Generic.xaml,这个是默认的控件样式定义的文件。创建的界面如下:

2.jpg

修改文件名为FlatButton,并继承自Button控件,FlatButton.cs示例代码如下:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Yd.WpfControls
{
    public class FlatButton : Button
    {
        static FlatButton()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(FlatButton), 
                new FrameworkPropertyMetadata(typeof(FlatButton)));
        }
        //自定义控件属性ButtonType,其DependencyProperty为ButtonType+Property
        public static readonly DependencyProperty ButtonTypeProperty =
           DependencyProperty.Register("ButtonType", typeof(FlatButtonType), typeof(FlatButton), 
               new PropertyMetadata(FlatButtonType.Default));

        public FlatButtonType ButtonType
        {
            get { return (FlatButtonType)GetValue(ButtonTypeProperty); }
            set { SetValue(ButtonTypeProperty, value); }
        }

        public static readonly DependencyProperty MouseOverBackgroundProperty =
            DependencyProperty.Register("MouseOverBackground", typeof(Brush), typeof(FlatButton),
                new PropertyMetadata(Brushes.RoyalBlue));

        public Brush MouseOverBackground
        {
            get { return (Brush)GetValue(MouseOverBackgroundProperty); }
            set { SetValue(MouseOverBackgroundProperty, value); }
        }

        public static readonly DependencyProperty MouseOverForegroundProperty =
            DependencyProperty.Register("MouseOverForeground", typeof(Brush), typeof(FlatButton),
                new PropertyMetadata(Brushes.White));

        public Brush MouseOverForeground
        {
            get { return (Brush)GetValue(MouseOverForegroundProperty); }
            set { SetValue(MouseOverForegroundProperty, value); }
        }

        public static readonly DependencyProperty CornerRadiusProperty =
            DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(FlatButton),
                new PropertyMetadata(new CornerRadius(2)));
        public CornerRadius CornerRadius
        {
            get { return (CornerRadius)GetValue(CornerRadiusProperty); }
            set { SetValue(CornerRadiusProperty, value); }
        }
    }
}

FlatButton的UI定义基本都是靠样式定义文件FlatButton.xaml,其类似于CSS,但是语法描述不同。FlatButton.xaml位于Style目录下,其示例代码如下:

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

    <Style TargetType="{x:Type local:FlatButton}">
        <Setter Property="FontSize" Value="{x:Static local:FlatFonts.contentFontSize}"/>
        <Setter Property="FontFamily" Value="{x:Static local:FlatFonts.contentFontFamily}"/>
        <Style.Triggers>
            <Trigger Property="ButtonType" Value="Default">
                <Setter Property="Background" Value="{x:Static local:FlatColors.PETER_RIVER}"/>
                <Setter Property="Foreground" Value="{x:Static local:FlatColors.CLOUDS}"/>
                <Setter Property="MouseOverBackground" Value="{x:Static local:FlatColors.BELIZE_HOLE}"/>
                <Setter Property="MouseOverForeground" Value="{x:Static local:FlatColors.CLOUDS}"/>
                <Setter Property="BorderBrush" Value="Transparent"/>
                <Setter Property="BorderThickness" Value="0"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type local:FlatButton}">
                            <Border x:Name="border" Background="{TemplateBinding Background}" CornerRadius="{TemplateBinding CornerRadius}"  BorderThickness="{TemplateBinding BorderThickness}" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" SnapsToDevicePixels="True">
                                <TextBlock x:Name="text" Text="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
                            </Border>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsMouseOver" Value="True">
                                    <Setter TargetName="border" Property="Background" Value="{Binding MouseOverBackground,RelativeSource={RelativeSource TemplatedParent}}"/>
                                    <Setter TargetName="text" Property="Foreground" Value="{Binding MouseOverForeground,RelativeSource={RelativeSource TemplatedParent}}"/>
                                 </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Trigger>
            <Trigger Property="ButtonType" Value="Warn">
                <Setter Property="Background" Value="#f1c40f"/>
                <Setter Property="MouseOverBackground" Value="#f39c12"/>
                <Setter Property="Foreground" Value="{x:Static local:FlatColors.CLOUDS}"/>
                <Setter Property="MouseOverForeground" Value="#ecf0f1"/>
                <Setter Property="BorderBrush" Value="Transparent"/>
                <Setter Property="BorderThickness" Value="0"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type local:FlatButton}">
                            <Border x:Name="border" Background="{TemplateBinding Background}" CornerRadius="{TemplateBinding CornerRadius}" BorderThickness="{TemplateBinding BorderThickness}" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" SnapsToDevicePixels="True">
                                <TextBlock x:Name="text" Text="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
                            </Border>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsMouseOver" Value="True">
                                    <Setter TargetName="border" Property="Background" Value="{Binding MouseOverBackground,RelativeSource={RelativeSource TemplatedParent}}"/>
                                    <Setter TargetName="text" Property="Foreground" Value="{Binding MouseOverForeground,RelativeSource={RelativeSource TemplatedParent}}"/>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Trigger>
            <Trigger Property="ButtonType" Value="Danger">
                <Setter Property="Background" Value="#c0392b"/>
                <Setter Property="MouseOverBackground" Value="#e74c3c"/>
                <Setter Property="Foreground" Value="{x:Static local:FlatColors.CLOUDS}"/>
                <Setter Property="MouseOverForeground" Value="#ecf0f1"/>
                <Setter Property="BorderBrush" Value="Transparent"/>
                <Setter Property="BorderThickness" Value="0"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type local:FlatButton}">
                            <Border x:Name="border" Background="{TemplateBinding Background}" CornerRadius="{TemplateBinding CornerRadius}"  BorderThickness="{TemplateBinding BorderThickness}" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" SnapsToDevicePixels="True">
                                <TextBlock x:Name="text" Text="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
                            </Border>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsMouseOver" Value="True">
                                    <Setter TargetName="border" Property="Background" Value="{Binding MouseOverBackground,RelativeSource={RelativeSource TemplatedParent}}"/>
                                    <Setter TargetName="text" Property="Foreground" Value="{Binding MouseOverForeground,RelativeSource={RelativeSource TemplatedParent}}"/>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Trigger>
        </Style.Triggers>
    </Style>
</ResourceDictionary>

此样式定义中,首先需要明确样式是针对哪个控件的,其用如下命令指定:

<Style TargetType="{x:Type local:FlatButton}">

local这个命名空间是在 xmlns:local="clr-namespace:Yd.WpfControls" 进行定义的,这个需要手动添加,否则内部找不到FlatButton空间。在样式表中,可以对属性进行绑定,其中的属性可以是自定义的属性,比如:

<Trigger Property="ButtonType" Value="Default">

也可以绑定到静态类对象中,比如前面定义的颜色笔刷和字体对象,如:

<Setter Property="Background" Value="{x:Static local:FlatColors.PETER_RIVER}"/>
<Setter Property="FontSize" Value="{x:Static local:FlatFonts.contentFontSize}"/>
<Setter Property="FontFamily" Value="{x:Static local:FlatFonts.contentFontFamily}"/>

第三步,将样式FlatButton.xaml添加到默认的Generic.xaml中,否则则UI无法加载样式定义信息Generic.xaml其代码如下:

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

    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="/Yd.WpfControls;component/Style/FlatButton.xaml"/>
    </ResourceDictionary.MergedDictionaries>

</ResourceDictionary>

注意:ResourceDictionary Source的定义中,/Yd.WpfControls;component/+样式表路径,这个前缀不可少。

第四步,编译后,可以将自定义控件添加到UI界面上,如下所示:

3.jpg

选中某个FlatButton控件,可以在属性窗口中进行属性设置,其中也包含自定义的属性,示例如下:

4.jpg

主界面窗口的示例代码如下:

<Window
        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:WpfControls="clr-namespace:Yd.WpfControls;assembly=Yd.WpfControls" 
        x:Class="WpfControls.MainWindow"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>

        <WpfControls:FlatButton Content="确定" HorizontalAlignment="Left" Height="37" Margin="89,83,0,0" VerticalAlignment="Top"  ButtonType="Default" CornerRadius="18" Width="120" FontFamily="Microsoft YaHei" FontSize="16"/>
        <WpfControls:FlatButton Content="取消" HorizontalAlignment="Left" Margin="412,88,0,0" VerticalAlignment="Top" Height="32"  ButtonType="Warn" CornerRadius="18" Width="120" FontFamily="Microsoft YaHei" FontSize="16" Click="FlatButton_Click"/>
        <WpfControls:FlatButton Content="删除" HorizontalAlignment="Left" Margin="249,88,0,0" VerticalAlignment="Top" Height="32"  ButtonType="Danger" CornerRadius="0" Width="120" x:Name="btn01" FontFamily="Microsoft YaHei" FontSize="16"/>
        <WpfControls:FlatButton Content="FlatButton" HorizontalAlignment="Left" Margin="72,0,0,0" VerticalAlignment="Center" Height="37" Width="137"/>

    </Grid>
</Window>

第五步,编译运行,主界面如下:

5.jpg

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。