WPFプログラミング備忘録

WPF デフォルトのスタイルの適用について

WPF

この記事では複数のコントロールに一括してスタイルを適用する方法について確認します。

ボタンとスタイルの定義

まず以下のとおり9つのボタンとスタイルを定義します。スタイルはリソースとして定義します。

BasedOnプロパティによってスタイルを継承できます。

ただしTargetTypeプロパティに指定できる値は、BasedOnプロパティに指定したスタイルのTargetTypeプロパティのクラスまたはその派生クラスのみです。

ButtonクラスはFrameworkElementクラスの派生クラスなのでbaseButtonStyleスタイルのBasedOnプロパティにsizeStyleスタイルを指定できます。

<Window x:Class="WpfDefaultStyle.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:WpfDefaultStyle"
        mc:Ignorable="d"
        Title="DefaultStyleSample" Height="450" Width="800">
    <Window.Resources>
        <Style x:Key="sizeStyle" TargetType="FrameworkElement">
            <Setter Property="Width" Value="120" />
            <Setter Property="Height" Value="40" />
        </Style>
        <Style x:Key="baseButtonStyle" TargetType="Button" BasedOn="{StaticResource sizeStyle}">
            <Setter Property="FontFamily" Value="MS UI Gothic" />
            <Setter Property="FontSize" Value="20" />
        </Style>
        <Style x:Key="colorfulButtonStyle" TargetType="Button" BasedOn="{StaticResource baseButtonStyle}">
            <Setter Property="Background">
                <Setter.Value>
                    <LinearGradientBrush>
                        <GradientStop Offset="0" Color="SkyBlue" />
                        <GradientStop Offset="1" Color="GreenYellow" />
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        
        <Button Grid.Row="0" Grid.Column="0" Content="ボタン1" />
        <Button Grid.Row="0" Grid.Column="1" Content="ボタン2" />
        <Button Grid.Row="0" Grid.Column="2" Content="ボタン3" />
        <Button Grid.Row="1" Grid.Column="0" Content="ボタン4" />
        <Button Grid.Row="1" Grid.Column="1" Content="ボタン5" />
        <Button Grid.Row="1" Grid.Column="2" Content="ボタン6" />
        <Button Grid.Row="2" Grid.Column="0" Content="ボタン7" />
        <Button Grid.Row="2" Grid.Column="1" Content="ボタン8" />
        <Button Grid.Row="2" Grid.Column="2" Content="ボタン9" />
    </Grid>
</Window>

このプログラムの実行結果は以下のとおりです。スタイルが何も適用されていないことがわかります。

通常のスタイルの適用方法

では9つのボタンに同じスタイルを適用してみます。通常は以下のようにButtonコントロールにStyleプロパティを適用します。

<Window x:Class="WpfDefaultStyle.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:WpfDefaultStyle"
        mc:Ignorable="d"
        Title="DefaultStyleSample" Height="450" Width="800">
    <Window.Resources>
        <Style x:Key="sizeStyle" TargetType="FrameworkElement">
            <Setter Property="Width" Value="120" />
            <Setter Property="Height" Value="40" />
        </Style>
        <Style x:Key="baseButtonStyle" TargetType="Button" BasedOn="{StaticResource sizeStyle}">
            <Setter Property="FontFamily" Value="MS UI Gothic" />
            <Setter Property="FontSize" Value="20" />
        </Style>
        <Style x:Key="colorfulButtonStyle" TargetType="Button" BasedOn="{StaticResource baseButtonStyle}">
            <Setter Property="Background">
                <Setter.Value>
                    <LinearGradientBrush>
                        <GradientStop Offset="0" Color="SkyBlue" />
                        <GradientStop Offset="1" Color="GreenYellow" />
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>

        <Button Grid.Row="0" Grid.Column="0" Content="ボタン1" Style="{StaticResource colorfulButtonStyle}" />
        <Button Grid.Row="0" Grid.Column="1" Content="ボタン2" Style="{StaticResource colorfulButtonStyle}" />
        <Button Grid.Row="0" Grid.Column="2" Content="ボタン3" Style="{StaticResource colorfulButtonStyle}" />
        <Button Grid.Row="1" Grid.Column="0" Content="ボタン4" Style="{StaticResource colorfulButtonStyle}" />
        <Button Grid.Row="1" Grid.Column="1" Content="ボタン5" Style="{StaticResource colorfulButtonStyle}" />
        <Button Grid.Row="1" Grid.Column="2" Content="ボタン6" Style="{StaticResource colorfulButtonStyle}" />
        <Button Grid.Row="2" Grid.Column="0" Content="ボタン7" Style="{StaticResource colorfulButtonStyle}" />
        <Button Grid.Row="2" Grid.Column="1" Content="ボタン8" Style="{StaticResource colorfulButtonStyle}" />
        <Button Grid.Row="2" Grid.Column="2" Content="ボタン9" Style="{StaticResource colorfulButtonStyle}" />
    </Grid>
</Window>

実行結果は以下のとおりです。正常にスタイルが適用されているのがわかります。

デフォルトのスタイルの適用方法

先ほどの方法でもスタイルは適用できますが、実はButtonコントロールのStyleプロパティを省略することができます。

そのためには colorfulButtonStyle スタイルから x:Key 属性を削除します。XAMLファイルは以下のとおりです。

<Window x:Class="WpfDefaultStyle.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:WpfDefaultStyle"
        mc:Ignorable="d"
        Title="DefaultStyleSample" Height="450" Width="800">
    <Window.Resources>
        <Style x:Key="sizeStyle" TargetType="FrameworkElement">
            <Setter Property="Width" Value="120" />
            <Setter Property="Height" Value="40" />
        </Style>
        <Style x:Key="baseButtonStyle" TargetType="Button" BasedOn="{StaticResource sizeStyle}">
            <Setter Property="FontFamily" Value="MS UI Gothic" />
            <Setter Property="FontSize" Value="20" />
        </Style>
        <Style TargetType="Button" BasedOn="{StaticResource baseButtonStyle}"><!-- x:Key属性を削除 -->
            <Setter Property="Background">
                <Setter.Value>
                    <LinearGradientBrush>
                        <GradientStop Offset="0" Color="SkyBlue" />
                        <GradientStop Offset="1" Color="GreenYellow" />
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        
        <Button Grid.Row="0" Grid.Column="0" Content="ボタン1" />
        <Button Grid.Row="0" Grid.Column="1" Content="ボタン2" />
        <Button Grid.Row="0" Grid.Column="2" Content="ボタン3" />
        <Button Grid.Row="1" Grid.Column="0" Content="ボタン4" />
        <Button Grid.Row="1" Grid.Column="1" Content="ボタン5" />
        <Button Grid.Row="1" Grid.Column="2" Content="ボタン6" />
        <Button Grid.Row="2" Grid.Column="0" Content="ボタン7" />
        <Button Grid.Row="2" Grid.Column="1" Content="ボタン8" />
        <Button Grid.Row="2" Grid.Column="2" Content="ボタン9" />
    </Grid>
</Window>

x:Key属性の無いスタイルはデフォルトのスタイルとなるのです。

つまりスタイルを明示的に指定していないButtonコントロールには x:Key 属性の無いスタイルが適用されます。

実行結果は以下のとおりです。

先ほどButtonコントロールに明示的にスタイルを指定していた時と同じ結果になります。

デフォルトのスタイルの適用を解除

ここで特定のButtonだけデフォルトのスタイルを適用をしたくない場合はどうすればよいのでしょうか?

例えば真ん中のボタン5だけデフォルトのスタイルを適用したくない場合は

Style="{x:Null}"

と指定すればよいのです。 XAMLファイルは以下のとおりです。

<Window x:Class="WpfDefaultStyle.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:WpfDefaultStyle"
        mc:Ignorable="d"
        Title="DefaultStyleSample" Height="450" Width="800">
    <Window.Resources>
        <Style x:Key="sizeStyle" TargetType="FrameworkElement">
            <Setter Property="Width" Value="120" />
            <Setter Property="Height" Value="40" />
        </Style>
        <Style x:Key="baseButtonStyle" TargetType="Button" BasedOn="{StaticResource sizeStyle}">
            <Setter Property="FontFamily" Value="MS UI Gothic" />
            <Setter Property="FontSize" Value="20" />
        </Style>
        <Style TargetType="Button" BasedOn="{StaticResource baseButtonStyle}"><!-- x:Key属性を削除 -->
            <Setter Property="Background">
                <Setter.Value>
                    <LinearGradientBrush>
                        <GradientStop Offset="0" Color="SkyBlue" />
                        <GradientStop Offset="1" Color="GreenYellow" />
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        
        <Button Grid.Row="0" Grid.Column="0" Content="ボタン1" />
        <Button Grid.Row="0" Grid.Column="1" Content="ボタン2" />
        <Button Grid.Row="0" Grid.Column="2" Content="ボタン3" />
        <Button Grid.Row="1" Grid.Column="0" Content="ボタン4" />
        <Button Grid.Row="1" Grid.Column="1" Content="ボタン5" Style="{x:Null}" />
        <Button Grid.Row="1" Grid.Column="2" Content="ボタン6" />
        <Button Grid.Row="2" Grid.Column="0" Content="ボタン7" />
        <Button Grid.Row="2" Grid.Column="1" Content="ボタン8" />
        <Button Grid.Row="2" Grid.Column="2" Content="ボタン9" />
    </Grid>
</Window>

実行結果は以下のとおりです。

ボタン5のスタイルが無効になっていることがわかります。あるいは別のスタイルを明示的に指定しても構いません。

継承元のスタイルをデフォルトスタイルにする

最後に、baseButtonStyleスタイルをデフォルトのスタイルにして、ボタン5だけをカラフルなボタンにしたい場合を考えます。下図の画面を作りたい場合です。

まず、デフォルトのスタイルがbaseButtonStyleスタイルに変わるので、ここから x:Key 属性を削除します。

<Style TargetType="Button" BasedOn="{StaticResource sizeStyle}"><!-- x:Key属性を削除 -->
    <Setter Property="FontFamily" Value="MS UI Gothic" />
    <Setter Property="FontSize" Value="20" />
</Style>

次にボタン5のためにcolorfulButtonStyleスタイルには x:Key 属性を復活させます。しかし、一つ問題があります。BasedOnプロパティに継承元のデフォルトスタイルのキーを指定したいのですが、上記のとおり継承元のスタイルからは x:Key 属性が削除されたため以下のようには出来ません。

<Style x:Key="colorfulButtonStyle" TargetType="Button" BasedOn="{StaticResource baseButtonStyle"><!-- baseButtonStyleキーは存在しないためNG -->
    <Setter Property="Background">
        <Setter.Value>
            <LinearGradientBrush>
                <GradientStop Offset="0" Color="SkyBlue" />
                <GradientStop Offset="1" Color="GreenYellow" />
            </LinearGradientBrush>
        </Setter.Value>
    </Setter>
</Style>

これは実行時エラーとなります。

このような場合は、x:Type を使うことによってデフォルトのスタイルを継承することが出来ます。

<Style x:Key="colorfulButtonStyle" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
    <Setter Property="Background">
        <Setter.Value>
            <LinearGradientBrush>
                <GradientStop Offset="0" Color="SkyBlue" />
                <GradientStop Offset="1" Color="GreenYellow" />
            </LinearGradientBrush>
        </Setter.Value>
    </Setter>
</Style>

上記を反映したXAMLファイルは以下のとおりです。

<Window x:Class="WpfDefaultStyle.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:WpfDefaultStyle"
        mc:Ignorable="d"
        Title="DefaultStyleSample" Height="450" Width="800">
    <Window.Resources>
        <Style x:Key="sizeStyle" TargetType="FrameworkElement">
            <Setter Property="Width" Value="120" />
            <Setter Property="Height" Value="40" />
        </Style>
        <Style TargetType="Button" BasedOn="{StaticResource sizeStyle}"><!-- デフォルトのスタイル -->
            <Setter Property="FontFamily" Value="MS UI Gothic" />
            <Setter Property="FontSize" Value="20" />
        </Style>
        <Style x:Key="colorfulButtonStyle" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
            <Setter Property="Background">
                <Setter.Value>
                    <LinearGradientBrush>
                        <GradientStop Offset="0" Color="SkyBlue" />
                        <GradientStop Offset="1" Color="GreenYellow" />
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        
        <Button Grid.Row="0" Grid.Column="0" Content="ボタン1" />
        <Button Grid.Row="0" Grid.Column="1" Content="ボタン2" />
        <Button Grid.Row="0" Grid.Column="2" Content="ボタン3" />
        <Button Grid.Row="1" Grid.Column="0" Content="ボタン4" />
        <Button Grid.Row="1" Grid.Column="1" Content="ボタン5" Style="{StaticResource colorfulButtonStyle}" />
        <Button Grid.Row="1" Grid.Column="2" Content="ボタン6" />
        <Button Grid.Row="2" Grid.Column="0" Content="ボタン7" />
        <Button Grid.Row="2" Grid.Column="1" Content="ボタン8" />
        <Button Grid.Row="2" Grid.Column="2" Content="ボタン9" />
    </Grid>
</Window>

今回は複数のコントロールに一括してスタイルを適用する方法について確認しました。

なお、今回は一つのファイルにスタイル定義とコントロールを配置しましたが、スタイル定義をアプリケーション全体で使用できるようにする方法については以下の記事をご確認ください。

>>WPF スタイル定義ファイルの共通化

以上です。

コメント