WPFのCheckBoxはシンプルで業務システム向けですが、最近のアプリではマテリアルデザイン風のモダンなUIが求められることも多いです。よってこの記事ではよりモダンなCheckBoxのスタイルを定義する方法を解説していきたいと思います。次の流れで解説をおこないます。
この記事で作成するもの

この記事では、上記のマテリアルデザイン風CheckBoxのスタイルを作成します。ホバーしたときやフォーカスがあたっているときの状態変化にも対応します。
CheckBoxのスタイル定義
スタイルの作成と適用方法の詳しい解説はこちらの記事を参照ください。ここではCheckBoxのスタイルを変更してモダンなスタイルを作っていきます。
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:o="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="FocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Margin="0" StrokeDashArray="1 2" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" SnapsToDevicePixels="true" StrokeThickness="1"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<SolidColorBrush x:Key="OptionMark.Static.Background" Color="Transparent" o:Freeze="True"/>
<SolidColorBrush x:Key="OptionMark.Static.Glyph" Color="#FFFFFFFF" o:Freeze="True"/>
<SolidColorBrush x:Key="OptionMark.MouseOver.Background" Color="Transparent" o:Freeze="True"/>
<SolidColorBrush x:Key="CheckBoxBorder.Checked.Background" Color="#CC673AB7" o:Freeze="True"/>
<SolidColorBrush x:Key="CheckBoxBorder.Null.Background" Color="#CC673AB7" o:Freeze="True"/>
<SolidColorBrush x:Key="Circle.MouseOver.Background" Color="#44673AB7" o:Freeze="True"/>
<SolidColorBrush x:Key="Circle.Pressed.Background" Color="#55673AB7" o:Freeze="True"/>
<SolidColorBrush x:Key="Circle.Focused.Background" Color="#44673AB7" o:Freeze="True"/>
<SolidColorBrush x:Key="Circle.Focused.BorderBrush" Color="#CC673AB7" o:Freeze="True"/>
<Style x:Key="CheckBox" TargetType="{x:Type CheckBox}">
<Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
<Setter Property="Background" Value="{StaticResource OptionMark.Static.Background}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid x:Name="templateRoot" Background="Transparent" SnapsToDevicePixels="True">
<DockPanel HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<Border x:Name="Circle" DockPanel.Dock="Left" Width="48" Height="48" Background="Transparent" CornerRadius="100" BorderThickness="1">
<Border x:Name="checkBoxBorder" Width="18" Height="18" Background="{TemplateBinding Background}" BorderBrush="{StaticResource CheckBoxBorder.Checked.Background}" BorderThickness="{TemplateBinding BorderThickness}" HorizontalAlignment="Center" Margin="1" VerticalAlignment="Center" CornerRadius="2">
<Grid x:Name="markGrid">
<Path x:Name="optionMark" Data="F1 M 9.97498,1.22334L 4.6983,9.09834L 4.52164,9.09834L 0,5.19331L 1.27664,3.52165L 4.255,6.08833L 8.33331,1.52588e-005L 9.97498,1.22334 Z " Fill="{StaticResource OptionMark.Static.Glyph}" Margin="1" Opacity="0" Stretch="None" VerticalAlignment="Center" HorizontalAlignment="Center"/>
<Rectangle x:Name="indeterminateMark" Fill="{StaticResource OptionMark.Static.Glyph}" Margin="2" Opacity="0" Height="2"/>
</Grid>
</Border>
</Border>
<ContentPresenter x:Name="contentPresenter" Grid.Column="1" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</DockPanel>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasContent" Value="true">
<Setter Property="Padding" Value="4,0,0,0"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" TargetName="Circle" Value="{StaticResource Circle.MouseOver.Background}"/>
<Setter Property="Background" TargetName="checkBoxBorder" Value="{StaticResource OptionMark.MouseOver.Background}"/>
</Trigger>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Background" TargetName="Circle" Value="{StaticResource Circle.Focused.Background}"/>
<Setter Property="BorderBrush" TargetName="Circle" Value="{StaticResource Circle.Focused.BorderBrush}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" Value="0.56"/>
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter Property="Background" TargetName="Circle" Value="{StaticResource Circle.Pressed.Background}"/>
</Trigger>
<Trigger Property="IsChecked" Value="true">
<Setter Property="Opacity" TargetName="optionMark" Value="1"/>
<Setter Property="Opacity" TargetName="indeterminateMark" Value="0"/>
<Setter Property="Background" TargetName="checkBoxBorder" Value="{StaticResource CheckBoxBorder.Checked.Background}"/>
</Trigger>
<Trigger Property="IsChecked" Value="{x:Null}">
<Setter Property="Opacity" TargetName="optionMark" Value="0"/>
<Setter Property="Opacity" TargetName="indeterminateMark" Value="1"/>
<Setter Property="Background" TargetName="checkBoxBorder" Value="{StaticResource CheckBoxBorder.Null.Background}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
CheckBoxのスタイル適用方法
作成したスタイルをCheckBoxのスタイルに適用していきます。適用方法は下記の通りです。
<CheckBox
Style="{StaticResource CheckBox}"
IsChecked="True"
Content="ON"/>
注意点
- App.xamlの辞書に、定義したチェックボックスのスタイルファイルを登録し忘れないようにする(詳細についてはこちらの記事を参照)
- チェックボックスの状態を意識して色を定義すると実用的になる