C#のWPFでチェックボックスのデザインをカスタマイズ

CheckBoxコントロールのチェックする部分のデザインを変えてみる。

 

以前、チェックボックス付きのTreeViewを作成し、IsCheckedプロパティのTrue,False,Nullの3形状を使い分けていたが、Nullの時の見た目が分かりずらい気がしたのでデザインをカスタマイズする。

 

↓こんな感じ。

 

 

 

 

上の4つは、デフォルトの状態。

(OSによってデザインが変わるかも)

 

下4つがカスタマイズしたデザイン。

XAML

<Window x:Class="WpfApplication1.MainWindow"
        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:local="clr-namespace:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="250" Width="250">
    <Window.Resources>
        <Style x:Key="CustomStyle" TargetType="{x:Type CheckBox}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type CheckBox}">
                        <BulletDecorator>
                            <BulletDecorator.Bullet>
                                <Grid>
                                    <Grid x:Name="EnableTrue" Width="17" Height="14">
                                        <Rectangle x:Name="CheckNull" Width="12" Height="12" HorizontalAlignment="Left" VerticalAlignment="Center" Fill="LightGray" Stroke="Gray" StrokeThickness="1"/>
                                        <Rectangle x:Name="CheckRect" Width="12" Height="12" HorizontalAlignment="Left" VerticalAlignment="Center" Fill="White" Stroke="LightGray" StrokeThickness="1"/>
                                        <Path x:Name="CheckMark" IsHitTestVisible="False" SnapsToDevicePixels="False" StrokeThickness="2" Data="M 3 5 L 5 8 L 13 0" Stroke="SteelBlue"/>
                                    </Grid>
                                    <Grid x:Name="EnableFalse" Width="17">
                                        <Rectangle Width="12" Height="12" HorizontalAlignment="Left" VerticalAlignment="Center" Fill="WhiteSmoke" Stroke="Gray" StrokeThickness="1" StrokeDashArray="1,3"/>
                                    </Grid>
                                </Grid>
                            </BulletDecorator.Bullet>
                            <BulletDecorator.Child>
                                <ContentPresenter/>
                            </BulletDecorator.Child>
                        </BulletDecorator>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsEnabled" Value="True">
                                <Setter TargetName="EnableTrue" Property="Visibility" Value="Visible" />
                                <Setter TargetName="EnableFalse" Property="Visibility" Value="Collapsed" />
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="False">
                                <Setter TargetName="EnableTrue" Property="Visibility" Value="Collapsed" />
                                <Setter TargetName="EnableFalse" Property="Visibility" Value="Visible" />
                                <Setter Property="Foreground" Value="Gray"/>
                            </Trigger>
                            <Trigger Property="IsChecked" Value="{x:Null}">
                                <Setter TargetName="CheckNull" Property="Visibility" Value="Visible" />
                                <Setter TargetName="CheckRect" Property="Visibility" Value="Collapsed" />
                                <Setter TargetName="CheckMark" Property="Visibility" Value="Visible" />
                            </Trigger>
                            <Trigger Property="IsChecked" Value="True">
                                <Setter TargetName="CheckNull" Property="Visibility" Value="Collapsed" />
                                <Setter TargetName="CheckRect" Property="Visibility" Value="Visible" />
                                <Setter TargetName="CheckMark" Property="Visibility" Value="Visible" />
                            </Trigger>
                            <Trigger Property="IsChecked" Value="False">
                                <Setter TargetName="CheckNull" Property="Visibility" Value="Collapsed" />
                                <Setter TargetName="CheckRect" Property="Visibility" Value="Visible" />
                                <Setter TargetName="CheckMark" Property="Visibility" Value="Hidden" />
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <StackPanel Margin="20">
        <CheckBox IsChecked="True">Checked…True</CheckBox>
        <CheckBox IsChecked="False">Checked…False</CheckBox>
        <CheckBox IsChecked="{x:Null}">Checked…Null</CheckBox>
        <CheckBox IsChecked="True" IsEnabled="False">Enabled…False</CheckBox>
        <Separator Margin="5"/>
        <CheckBox Style="{StaticResource CustomStyle}" IsChecked="True">Checked…True</CheckBox>
        <CheckBox Style="{StaticResource CustomStyle}" IsChecked="False">Checked…False</CheckBox>
        <CheckBox Style="{StaticResource CustomStyle}" IsChecked="{x:Null}">Checked…Null</CheckBox>
        <CheckBox Style="{StaticResource CustomStyle}" IsChecked="True" IsEnabled="False">Enabled…False</CheckBox>
    </StackPanel>
</Window>

ControlTemplateを定義する (11~13行目)

CheckBoxのTemplateプロパティへControlTemplateを定義する。

 

 

BulletDecoratorを使う (14~30行目)

BulletDecoratorクラスを使ってレイアウトする。

このクラスは、行頭部分をデザインするBulletプロパティと、その後に続く部分のChildプロパティ持っている。

行頭部分にチェックを付けるところのデザインを配置。

後の部分にはContentPresenterを置く事で、CheckBoxのContentが使われるようににする。

 

Bullet内には「EnableTrue」と「EnableFalse」という名前を付けたGridを作っている。

後述するTriggerによって、CheckBoxのIsEnabledプロパティがTrueの時とFalseの時で表示するGridを切り替えるようになっている。

 

「EnableTrue」の方のGridには、IsCheckedプロパティがNullの時用のRectangleと、それ以外の時用のRectangleと、Trueの時用のチェックマークを作っている。

これもTriggerによって、それぞれの表示する・しないを切り替えるようになっている。

 

 

Treggerを使ってIsEnabledの状態別にデザインを切り替える (32~40行目)

IsEnabledプロパティがTrueの時は「EnableTrue」のGridを表示させ「EnableFalse」は消す。

IsEnabledプロパティがFalseの時は「EnableTrue」のGridを消して「EnableFalse」を表示。

Falseの時はForegroundプロパティも変える事でContent部分もグレーアウトしている。

 

 

Treggerを使ってIsCheckedの状態別にデザインを切り替える (41~55行目)

IsCheckedプロパティがTrueの時は「CheckRect」の四角と「CheckMark」を表示。

IsCheckedプロパティがNullの時は「CheckRect」の四角のみを表示。

IsCheckedプロパティがNullの時は「CheckNull」の四角と「CheckMark」を表示。