一.前言
申明: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="" 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="" TargetName="icon" ></Setter> <Setter Property="Foreground" Value="{StaticResource CheckedForeground}"></Setter> </Trigger> <Trigger Property="IsChecked" Value="{x:Null}"> <Setter Property="Text" Value="" 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))); } }
樣式代碼,狀態變換用了點小動畫,為了支持縮放,用了一個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>
使用示例:
<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="" 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="" 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="" 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自定義控件與樣式(3)-TextBox & RichTextBox & PasswordBox樣式、水印、Label標簽、功能擴展
版權所有,文章來源:http://www.cnblogs.com/anding
個人能力有限,本文內容僅供學習、探討,歡迎指正、交流。