[Transfer] WPF custom controls and styles (4)-CheckBox/RadioButton custom styles

one. Preface

Disclaimer: WPF custom controls and styles is a series of articles, which are somewhat related, but most of them are released gradually in the order from simple to complex, etc.

The main content of this article:

  • The custom style of the CheckBox check box can be implemented in two different styles;
  • RadioButton radio button custom style, there are two different styles to implement;

two. CheckBox custom style

2.1 CheckBox basic style

The standard CheckBox style code is as follows, which implements three-state display. The icons in different states use font icons (for font icons, you can refer to the appendix link at the end of this article)

<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=" & amp;#xe68b;"
                                        FontSize="{<!-- -->TemplateBinding local:ControlAttachProperty.FIconSize}"
                                        Margin="{<!-- -->TemplateBinding local:ControlAttachProperty.FIconMargin}"
                                        Foreground="{<!-- -->TemplateBinding Foreground}"/>
                            <ContentPresenter VerticalAlignment="Center"/>
                        </StackPanel>
                    </Grid>
                    <!--Trigger: Set selected status symbol-->
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked" Value="true">
                            <Setter Property="Text" Value=" & amp;#xe660;" TargetName="icon" ></Setter>
                            <Setter Property="Foreground" Value="{<!-- -->StaticResource CheckedForeground}"></Setter>
                        </Trigger>
                        <Trigger Property="IsChecked" Value="{<!-- -->x:Null}">
                            <Setter Property="Text" Value=" & amp;#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>

Usage examples and effects:

 <CheckBox Margin="3">Male</CheckBox>
            <CheckBox Margin="3">Female</CheckBox>
            <CheckBox Margin="3" IsChecked="{x:Null}">Other</CheckBox>
            <CheckBox Margin="3" IsChecked="{x:Null}">Female</CheckBox>
            <CheckBox Margin="3" IsEnabled="False">I am disabled</CheckBox>
            <CheckBox Margin="3" IsEnabled="False" IsChecked="{x:Null}">I am disabled</CheckBox>
            <CheckBox Margin="3" IsEnabled="False" IsChecked="True">I am disabled</CheckBox>

2.2 Another style of CheckBox

A common check effect on mobile terminals, let’s take a look at the effect first

This code was written a long time ago and implemented in the form of a control. It can be implemented in pure style, which is more concise and I am too lazy to change it. C# code:

/// <summary>
    /// Interaction logic of BulletCheckBox.xaml
    /// </summary>
    public class BulletCheckBox : CheckBox
    {
        public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
            "Text", typeof(string), typeof(BulletCheckBox), new PropertyMetadata("Off"));
        /// <summary>
        ///Default text (unselected)
        /// </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>
        /// Selected status text
        /// </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>
        /// Selected state foreground style
        /// </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>
        /// Selected status background color
        /// </summary>
        public Brush CheckedBackground
        {
            get { return (Brush)GetValue(CheckedBackgroundProperty); }
            set { SetValue(CheckedBackgroundProperty, value); }
        }

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

The style code uses a small animation for state transition. In order to support zooming, a Viewbox is used to wrap the content:

<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>
                <!--Control template-->
                <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">
                                <!--State ball-->
                                <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>
                                <!--Text box-->
                                <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>

                    <!--Trigger: Set selected status symbol-->
                    <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>

Usage example:

 <kc:BulletCheckBox />
            <kc:BulletCheckBox Text="Not enlightened" CheckedText="Open" IsChecked="True" />
            <kc:BulletCheckBox Text="Not enlightened" CheckedText="Open" IsChecked="True" Height="24" Width="60" />

three. RadioButton custom style

3.1 RadioButon basic style

The style of the standard radio control is very simple. Different icons are used to identify different states, and then triggers control the display effects of different states.

<!--Default style-->
    <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=" & amp;#xe63a;" Style="{<!-- -->StaticResource FIcon}" SnapsToDevicePixels="True"
                                       FontSize="{<!-- -->TemplateBinding local:ControlAttachProperty.FIconSize}"
                                        Margin="{<!-- -->TemplateBinding local:ControlAttachProperty.FIconMargin}"
                                        Foreground="{<!-- -->TemplateBinding Foreground}"/>
                            <ContentPresenter VerticalAlignment="Center"/>
                        </StackPanel>
                    </Grid>
                    <!--Trigger: Set selected status symbol-->
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked" Value="true">
                            <Setter Property="Text" Value=" & amp;#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>

Usage example:

 <RadioButton Margin="3" core:ControlAttachProperty.FIconSize="18">Male</RadioButton>
            <RadioButton Margin="3" core:ControlAttachProperty.FIconSize="20">Female</RadioButton>
            <RadioButton Margin="3" IsChecked="{x:Null}" core:ControlAttachProperty.FIconSize="22">Other</RadioButton>
            <RadioButton Margin="3" IsChecked="{x:Null}" core:ControlAttachProperty.FIconSize="24">Female</RadioButton>
            <RadioButton Margin="3" IsChecked="{x:Null}" core:ControlAttachProperty.FIconSize="26">Female</RadioButton>
            <RadioButton Margin="3" IsEnabled="False">I am disabled</RadioButton>
            <RadioButton Margin="3" IsEnabled="False" IsChecked="{x:Null}">I am disabled</RadioButton>

Rendering:

3.2 RadioButton Taobao, JD.com item size single item style

Let’s take a look at the effect first:

The style definition is also very simple. The small tick in the lower right corner uses a font icon, which can be resized as needed.

<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>
                        <!--Selected status identifier-->
                        <TextBlock Text=" & amp;#xe606;" x:Name="checkState" Style="{<!-- -->StaticResource FIcon}" VerticalAlignment="Bottom" Visibility="Collapsed"
                                   FontSize="14" Margin="1" HorizontalAlignment="Right" Foreground="{<!-- -->StaticResource CheckedForeground}"/>
                    </Grid>
                    <!--Trigger: Set selected status symbol-->
                    <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>

Sample code:

<RadioButton Style="{StaticResource BoxRadioButton}" Margin="1">Last 3 days</RadioButton>
<RadioButton Style="{StaticResource BoxRadioButton}" Margin="1">Last 7 days</RadioButton>
<RadioButton Style="{StaticResource BoxRadioButton}" Margin="1">This Month</RadioButton>
<RadioButton Style="{StaticResource BoxRadioButton}" Margin="1">Customized</RadioButton>
<RadioButton Style="{StaticResource BoxRadioButton}" Margin="1">2012.05.12-2015.12.14</RadioButton>

Supplementary explanation, additional attributes are used in the above style, such as

ControlAttachProperty.FIconMargin” Value=”1, 1, 3, 1″: Margin of check box or radio button font icon

ControlAttachProperty.FIconSize” Value=”25″: The size of the check box or radio button font icon

For additional attributes, please refer to the previous article (link at the end of this article), C# definition code:

#region FIconProperty Font Icon
        /// <summary>
        /// Font icon
        /// </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 Font icon size
        /// <summary>
        /// Font icon
        /// </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 Font icon margin
        /// <summary>
        /// Font icon
        /// </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

Original address: http://www.cnblogs.com/anding/p/4976559.html