[WPF/xaml]BasedOnを使って元のstyleを受け継ぐ


やりたいこと

複数の似たstyleを作るとなったときに、共通する部分だけ1つのstyleにまとめたい。

やり方

BasedOnを使う。

実験コード

下記のようなコードを書いて実験をした。
※Prismを使用しているので、画面はUserControlで作成。

UserControl1.xaml
<UserControl x:Class="PrismSample.Views.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:PrismSample.Views"
             xmlns:prism="http://prismlibrary.com/"
             prism:ViewModelLocator.AutoWireViewModel="True"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <UserControl.Resources>

        <!-- スタイル①:元になるスタイル -->
        <Style x:Key="MyButtonStyle" TargetType="Button">
            <Setter Property="Background" Value="Green"/>
            <Setter Property="Foreground" Value="Yellow"/>
            <Setter Property="BorderBrush" Value="Purple"/>
            <Setter Property="BorderThickness" Value="3"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Grid>
                            <Ellipse Stroke="{TemplateBinding BorderBrush}" Fill="{TemplateBinding Background}" 
                                     StrokeThickness="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Top}"/>
                            <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <!-- スタイル②:元のスタイルをベースに変更を加えるスタイル -->
        <Style x:Key="MyButtonStyleEx" TargetType="Button" BasedOn="{StaticResource MyButtonStyle}">
            <Setter Property="BorderBrush" Value="Red"/>
            <Setter Property="BorderThickness" Value="20"/>
        </Style>
    </UserControl.Resources>

    <!-- 画面表示メイン -->
    <Grid Background="Beige">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="360"/>
        </Grid.RowDefinitions>

        <TextBlock Grid.Row="0" Text="画面" FontSize="60"/>
        <Button Grid.Row="1" Content="ボタン" Command="{Binding ButtonCommand}" Style="{DynamicResource MyButtonStyleEx}"/>
    </Grid>
</UserControl>

実験内容

二つのstyleを定義し実験。それぞれ下記のようにしている。

スタイル①:元になるスタイル
ボタン淵色 :紫
ボタン淵太さ:3pixel
ボタン背景 :緑
ボタン文字 :黄色
→このstyle単体で表示させると下記のようになる。

スタイル②:元のスタイルをベースに変更を加えるスタイル
ボタン淵色 :赤
ボタン淵太さ:20
ボタン背景 :指定なし
ボタン文字 :指定なし
→このstyleで表示させると下記のようになる。

動作結果

BasedOnを使って元のstyleを受け継ぐと、受け継いだstyle側で指定したプロパティのみ上書きされ、そのほかのプロパティは元のstyleのままになる。

備考

スタイル①:元になるスタイルのほうで、Templateを指定していないと、WPF標準のButtonのstyleを受け継ぐことになる。その場合、マウスOverしたときとか無効になった時の色の変化も受け継がれる。(=Templateを指定すると、まったく何も受け継がなくなり、1から作成になるイメージ)

試しに、スタイル①:元になるスタイル<Setter Property="Template">のTemplate指定部分を丸ごと消すと、下記のようになる。

Templateで指定していたEllipseなどがなくなり、元のボタンのBorderTHicknessやBorderBrush、Backgroundが指定される形となる。
(マウスオーバー等させると、元のstyle通り、色も変わる)

参照

Button Class
https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.controls.button?view=netframework-4.8