WPF自定义控件与样式(4)-CheckBox/RadioButton自定义样式

简介: 原文:WPF自定义控件与样式(4)-CheckBox/RadioButton自定义样式一.前言   申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接。
原文: WPF自定义控件与样式(4)-CheckBox/RadioButton自定义样式

一.前言

  申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接。

本文主要内容:

  • CheckBox复选框的自定义样式,有两种不同的风格实现;
  • RadioButton单选框自定义样式,有两种不同的风格实现;

二. CheckBox自定义样式

2.1 CheckBox基本样式

标准CheckBox样式代码如下,实现了三态的显示,其中不同状态的图标用了字体图标(关于字体图标,可以参考本文末尾附录链接)  

    <Style x:Key="DefaultCheckBox" TargetType="{x:Type CheckBox}">
        <Setter Property="Background" Value="Transparent"></Setter>
        <Setter Property="Foreground" Value="{StaticResource TextForeground}"></Setter>
        <Setter Property="Padding" Value="0"></Setter>
        <Setter Property="local:ControlAttachProperty.FIconMargin" Value="1, 1, 3, 1"></Setter>
        <Setter Property="local:ControlAttachProperty.FIconSize" Value="22"></Setter>
        <Setter Property="FontSize" Value="{StaticResource FontSize}"></Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type CheckBox}">
                    <Grid x:Name="grid" Margin="{TemplateBinding Padding}" VerticalAlignment="Center">
                        <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
                            <TextBlock  x:Name="icon" Style="{StaticResource FIcon}" Text="&#xe68b;"
                                        FontSize="{TemplateBinding local:ControlAttachProperty.FIconSize}"
                                        Margin="{TemplateBinding local:ControlAttachProperty.FIconMargin}"
                                        Foreground="{TemplateBinding Foreground}"/>
                            <ContentPresenter VerticalAlignment="Center"/>
                        </StackPanel>
                    </Grid>
                    <!--触发器:设置选中状态符号-->
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked" Value="true">
                            <Setter Property="Text" Value="&#xe660;" TargetName="icon" ></Setter>
                            <Setter Property="Foreground" Value="{StaticResource CheckedForeground}"></Setter>
                        </Trigger>
                        <Trigger Property="IsChecked" Value="{x:Null}">
                            <Setter Property="Text" Value="&#xe68c;" TargetName="icon" ></Setter>
                        </Trigger>
                        <Trigger Property="IsMouseOver" Value="true">
                            <Setter Property="Foreground" Value="{StaticResource MouseOverForeground}"></Setter>
                        </Trigger>
                        <Trigger Property="IsEnabled" Value="False">
                            <Setter Property="Opacity" Value="{StaticResource DisableOpacity}" TargetName="grid" ></Setter>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

 使用示例及效果:  

            <CheckBox Margin="3"></CheckBox>
            <CheckBox Margin="3"></CheckBox>
            <CheckBox Margin="3" IsChecked="{x:Null}">其他</CheckBox>
            <CheckBox Margin="3" IsChecked="{x:Null}"></CheckBox>
            <CheckBox Margin="3" IsEnabled="False">我被禁用了</CheckBox>
            <CheckBox Margin="3" IsEnabled="False" IsChecked="{x:Null}">我被禁用了</CheckBox>
            <CheckBox Margin="3" IsEnabled="False" IsChecked="True">我被禁用了</CheckBox>

 

2.2 CheckBox另一种样式

在移动端比较常见的一种复选效果,先看看效果

 

这个代码是很久以前写的,用的控件的形式实现的,可以纯样式实现,更简洁,懒得改了。C#代码:  

    /// <summary>
    /// BulletCheckBox.xaml 的交互逻辑
    /// </summary>
    public class BulletCheckBox : CheckBox
    {
        public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
            "Text", typeof(string), typeof(BulletCheckBox), new PropertyMetadata("Off"));
        /// <summary>
        /// 默认文本(未选中)
        /// </summary>
        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        public static readonly DependencyProperty CheckedTextProperty = DependencyProperty.Register(
            "CheckedText", typeof(string), typeof(BulletCheckBox), new PropertyMetadata("On"));
        /// <summary>
        /// 选中状态文本
        /// </summary>
        public string CheckedText
        {
            get { return (string)GetValue(CheckedTextProperty); }
            set { SetValue(CheckedTextProperty, value); }
        }

        public static readonly DependencyProperty CheckedForegroundProperty =
            DependencyProperty.Register("CheckedForeground", typeof(Brush), typeof(BulletCheckBox), new PropertyMetadata(Brushes.WhiteSmoke));
        /// <summary>
        /// 选中状态前景样式
        /// </summary>
        public Brush CheckedForeground
        {
            get { return (Brush)GetValue(CheckedForegroundProperty); }
            set { SetValue(CheckedForegroundProperty, value); }
        }

        public static readonly DependencyProperty CheckedBackgroundProperty =
            DependencyProperty.Register("CheckedBackground", typeof(Brush), typeof(BulletCheckBox), new PropertyMetadata(Brushes.LimeGreen));
        /// <summary>
        /// 选中状态背景色
        /// </summary>
        public Brush CheckedBackground
        {
            get { return (Brush)GetValue(CheckedBackgroundProperty); }
            set { SetValue(CheckedBackgroundProperty, value); }
        }

        static BulletCheckBox()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(BulletCheckBox), new FrameworkPropertyMetadata(typeof(BulletCheckBox)));
        }
    }
View Code

样式代码,状态变换用了点小动画,为了支持缩放,用了一个Viewbox来包装内容:  

    <Style TargetType="{x:Type local:BulletCheckBox}">
        <Setter Property="Background" Value="#FF4A9E4A"></Setter>
        <Setter Property="Foreground" Value="#DDE8E1"></Setter>
        <Setter Property="CheckedForeground" Value="White"></Setter>
        <Setter Property="CheckedBackground" Value="#FF0CC50C"></Setter>
        <Setter Property="FontSize" Value="13"></Setter>
        <Setter Property="Cursor" Value="Hand"></Setter>
        <Setter Property="Width" Value="75"></Setter>
        <Setter Property="Height" Value="28"></Setter>
        <Setter Property="Margin" Value="1"></Setter>
        <Setter Property="Template">
            <Setter.Value>
                <!--控件模板-->
                <ControlTemplate TargetType="{x:Type local:BulletCheckBox}">
                    <Viewbox Stretch="Uniform"  VerticalAlignment="Center" HorizontalAlignment="Center">
                        <Border x:Name="border" Width="75" Height="28" Background="{TemplateBinding Background}" SnapsToDevicePixels="True"
                                Margin="{TemplateBinding Margin}" CornerRadius="14">
                            <StackPanel Orientation="Horizontal">
                                <!--状态球-->
                                <Border x:Name="state" Width="24" Height="24" Margin="3,2,1,2" CornerRadius="12" SnapsToDevicePixels="True"
                                    Background="{TemplateBinding Foreground}">
                                    <Border.RenderTransform>
                                        <TranslateTransform x:Name="transState" X="0"></TranslateTransform>
                                    </Border.RenderTransform>
                                </Border>
                                <!--文本框-->
                                <TextBlock Width="40" Foreground="{TemplateBinding Foreground}" x:Name="txt" Text="{TemplateBinding Text}" VerticalAlignment="Center" TextAlignment="Center">
                                    <TextBlock.RenderTransform>
                                        <TranslateTransform x:Name="transTxt" X="0"></TranslateTransform>
                                    </TextBlock.RenderTransform>
                                </TextBlock>
                            </StackPanel>
                        </Border>
                    </Viewbox>

                    <!--触发器:设置选中状态符号-->
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked" Value="True">
                            <Setter Property="Text" Value="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=CheckedText}" TargetName="txt"/>
                            <Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=CheckedForeground}" TargetName="state"/>
                            <Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=CheckedForeground}" TargetName="txt"/>
                            <Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=CheckedBackground}" TargetName="border"/>
                            <Trigger.EnterActions>
                                <BeginStoryboard>
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="transState" Storyboard.TargetProperty="X" To="45" Duration="0:0:0.2" />
                                        <DoubleAnimation Storyboard.TargetName="transTxt" Storyboard.TargetProperty="X" To="-24" Duration="0:0:0.2" />
                                    </Storyboard>
                                </BeginStoryboard>
                            </Trigger.EnterActions>
                            <Trigger.ExitActions>
                                <BeginStoryboard>
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="transState" Storyboard.TargetProperty="X" To="0" Duration="0:0:0.2" />
                                        <DoubleAnimation Storyboard.TargetName="transTxt" Storyboard.TargetProperty="X" To="0" Duration="0:0:0.2" />
                                    </Storyboard>
                                </BeginStoryboard>
                            </Trigger.ExitActions>
                        </Trigger>
                       
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Opacity" Value="{StaticResource DisableOpacity}" TargetName="border"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
View Code

使用示例:

            <kc:BulletCheckBox />
            <kc:BulletCheckBox Text="不开窍" CheckedText="开启" IsChecked="True" />
            <kc:BulletCheckBox Text="不开窍" CheckedText="开启" IsChecked="True" Height="24" Width="60" />
            <kc:BulletCheckBox Height="24" Width="60"/>

三.RadioButton自定义样式

3.1 RadioButon基本样式

标准单选控件的样式很简单,用不同图标标识不同状态,然后触发器控制不同状态的显示效果。  

    <!--默认样式-->
    <Style x:Key="DefaultRadioButton" TargetType="{x:Type RadioButton}">
        <Setter Property="Background" Value="Transparent"></Setter>
        <Setter Property="Foreground" Value="{StaticResource TextForeground}"></Setter>
        <Setter Property="Padding" Value="0"></Setter>
        <Setter Property="local:ControlAttachProperty.FIconMargin" Value="1, 1, 3, 1"></Setter>
        <Setter Property="local:ControlAttachProperty.FIconSize" Value="25"></Setter>
        <Setter Property="FontSize" Value="{StaticResource FontSize}"></Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type RadioButton}">
                    <Grid x:Name="grid" Margin="{TemplateBinding Padding}" VerticalAlignment="Center">
                        <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
                            <TextBlock x:Name="icon" Text="&#xe63a;" Style="{StaticResource FIcon}" SnapsToDevicePixels="True"
                                       FontSize="{TemplateBinding local:ControlAttachProperty.FIconSize}"
                                        Margin="{TemplateBinding local:ControlAttachProperty.FIconMargin}"
                                        Foreground="{TemplateBinding Foreground}"/>
                            <ContentPresenter VerticalAlignment="Center"/>
                        </StackPanel>
                    </Grid>
                    <!--触发器:设置选中状态符号-->
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked" Value="true">
                            <Setter Property="Text" Value="&#xe65c;" TargetName="icon" ></Setter>
                            <Setter Property="Foreground" Value="{StaticResource CheckedForeground}"></Setter>
                        </Trigger>
                        <Trigger Property="IsMouseOver" Value="true">
                            <Setter Property="Foreground" Value="{StaticResource MouseOverForeground}"></Setter>
                        </Trigger>
                        <Trigger Property="IsEnabled" Value="False">
                            <Setter Property="Opacity" Value="{StaticResource DisableOpacity}" TargetName="grid" ></Setter>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

使用示例:  

            <RadioButton Margin="3" core:ControlAttachProperty.FIconSize="18"></RadioButton>
            <RadioButton Margin="3" core:ControlAttachProperty.FIconSize="20"></RadioButton>
            <RadioButton Margin="3" IsChecked="{x:Null}" core:ControlAttachProperty.FIconSize="22">其他</RadioButton>
            <RadioButton Margin="3" IsChecked="{x:Null}" core:ControlAttachProperty.FIconSize="24"></RadioButton>
            <RadioButton Margin="3" IsChecked="{x:Null}" core:ControlAttachProperty.FIconSize="26"></RadioButton>
            <RadioButton Margin="3" IsEnabled="False">我被禁用了</RadioButton>
            <RadioButton Margin="3" IsEnabled="False" IsChecked="{x:Null}">我被禁用了</RadioButton>

效果图:

 

3.2 RadioButton淘宝、京东物品尺码单项样式

先看看效果:

 

样式定义也很简单,右下角那个小勾勾用的是一个字体图标,可以根据需要调整大小。  

    <Style x:Key="BoxRadioButton" TargetType="{x:Type RadioButton}">
        <Setter Property="Background" Value="Transparent"></Setter>
        <Setter Property="Foreground" Value="{StaticResource TextForeground}"></Setter>
        <Setter Property="Padding" Value="3 2 3 2"></Setter>
        <Setter Property="FontSize" Value="{StaticResource FontSize}"></Setter>
        <Setter Property="BorderThickness" Value="2"></Setter>
        <Setter Property="Height" Value="auto"></Setter>
        <Setter Property="SnapsToDevicePixels" Value="true"></Setter>
        <Setter Property="BorderBrush" Value="{StaticResource ControlBorderBrush}" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type RadioButton}">
                    <Grid x:Name="grid" VerticalAlignment="Center">
                        <Border BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}"  Height="{TemplateBinding Height}" HorizontalAlignment="Center"
                                Background="{TemplateBinding Background}" Width="{TemplateBinding Width}">
                            <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                        </Border>
                        <!--选中的状态标识-->
                        <TextBlock Text="&#xe606;" x:Name="checkState" Style="{StaticResource FIcon}" VerticalAlignment="Bottom" Visibility="Collapsed"
                                   FontSize="14" Margin="1" HorizontalAlignment="Right" Foreground="{StaticResource CheckedForeground}"/>
                    </Grid>
                    <!--触发器:设置选中状态符号-->
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked" Value="true">
                            <Setter Property="Visibility" Value="Visible" TargetName="checkState" ></Setter>
                            <Setter Property="BorderBrush" Value="{StaticResource CheckedForeground}"></Setter>
                        </Trigger>
                        <Trigger Property="IsMouseOver" Value="true">
                            <Setter Property="BorderBrush" Value="{StaticResource MouseOverForeground}"></Setter>
                        </Trigger>
                        <Trigger Property="IsEnabled" Value="False">
                            <Setter Property="Opacity" Value="{StaticResource DisableOpacity}" TargetName="grid" ></Setter>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

示例代码:  

<RadioButton Style="{StaticResource BoxRadioButton}" Margin="1">近3天</RadioButton>
<RadioButton Style="{StaticResource BoxRadioButton}" Margin="1">近7天</RadioButton>
<RadioButton Style="{StaticResource BoxRadioButton}" Margin="1">本月</RadioButton>
<RadioButton Style="{StaticResource BoxRadioButton}" Margin="1">自定义</RadioButton>
<RadioButton Style="{StaticResource BoxRadioButton}" Margin="1">2012.05.12-2015.12.14</RadioButton>

 

补充说明,上面样式中有用到附加属性,如

ControlAttachProperty.FIconMargin" Value="1, 1, 3, 1":复选框或单选框字体图标的边距

ControlAttachProperty.FIconSize" Value="25":复选框或单选框字体图标的大小

关于附加属性可以参考上一篇(本文末尾链接),C#定义代码:

        #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

 

附录:参考引用

WPF自定义控件与样式(1)-矢量字体图标(iconfont) 

WPF自定义控件与样式(2)-自定义按钮FButton

WPF自定义控件与样式(3)-TextBox & RichTextBox & PasswordBox样式、水印、Label标签、功能扩展   

 

版权所有,文章来源:http://www.cnblogs.com/anding

个人能力有限,本文内容仅供学习、探讨,欢迎指正、交流。

目录
相关文章
|
4月前
|
开发框架 缓存 前端开发
循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(11) -- 下拉列表的数据绑定以及自定义系统字典列表控件
循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(11) -- 下拉列表的数据绑定以及自定义系统字典列表控件
|
4月前
|
开发者 C# 存储
WPF开发者必读:资源字典应用秘籍,轻松实现样式与模板共享,让你的WPF应用更上一层楼!
【8月更文挑战第31天】在WPF开发中,资源字典是一种强大的工具,用于共享样式、模板、图像等资源,提高了应用的可维护性和可扩展性。本文介绍了资源字典的基础知识、创建方法及最佳实践,并通过示例展示了如何在项目中有效利用资源字典,实现资源的重用和动态绑定。
111 0
|
4月前
|
开发者 C# 存储
WPF开发者必读:样式与模板的艺术,轻松定制UI外观,让你的应用程序更上一层楼!
【8月更文挑战第31天】在WPF应用开发中,样式与模板是实现美观界面与一致性的关键工具。样式定义了控件如字体、颜色等属性,而模板则允许自定义控件布局与子控件,两者均可存储于`.xaml`文件中。本文介绍了样式与模板的基础知识,通过示例展示了如何创建并应用它们来改变按钮的外观,从而提升用户体验。
99 0
|
4月前
|
开发框架 前端开发 JavaScript
循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(3)--自定义用户控件
循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(3)--自定义用户控件
|
4月前
|
C#
WPF 自定义可拖动标题栏
WPF 自定义可拖动标题栏
54 0
|
4月前
|
存储 前端开发 C#
WPF/C#:更改界面的样式
WPF/C#:更改界面的样式
46 0
|
4月前
|
开发框架 前端开发 C#
使用WPF开发自定义用户控件,以及实现相关自定义事件的处理
使用WPF开发自定义用户控件,以及实现相关自定义事件的处理
|
7月前
|
C#
浅谈WPF之样式与资源
WPF通过样式,不仅可以方便的设置控件元素的展示方式,给用户呈现多样化的体验,还简化配置,避免重复设置元素的属性,以达到节约成本,提高工作效率的目的,样式也是资源的一种表现形式。本文以一个简单的小例子,简述如何设置WPF的样式以及资源的应用,仅供学习分享使用,如有不足之处,还请指正。
135 0
|
7月前
|
C# 开发者 Windows
基于Material Design风格开源、易用、强大的WPF UI控件库
基于Material Design风格开源、易用、强大的WPF UI控件库
398 0
|
7月前
|
C#
浅谈WPF之装饰器实现控件锚点
使用过visio的都知道,在绘制流程图时,当选择或鼠标移动到控件时,都会在控件的四周出现锚点,以便于修改大小,移动位置,或连接线等,那此功能是如何实现的呢?在WPF开发中,想要在控件四周实现锚点,可以通过装饰器来实现,今天通过一个简单的小例子,简述如何在WPF开发中,应用装饰器,仅供学习分享使用,如有不足之处,还请指正。
151 1