コントロールのスタイルを作成する方法 (WPF .NET)

Windows Presentation Foundation (WPF) を使用すると、独自の再利用可能なスタイルを使用して、既存のコントロールの外観をカスタマイズできます。 スタイルは、アプリ、ウィンドウ、ページにグローバルに適用することも、コントロールに直接適用することもできます。

スタイルの作成

Style は、一連のプロパティ値を 1 つ以上の要素に適用する便利な方法と考えることができます。 FrameworkElement または FrameworkContentElement から派生する任意の要素 (WindowButton など) にスタイルを使用できます。

スタイルを宣言する最も一般的な方法は、XAML ファイルの Resources セクションでリソースとして行うものです。 スタイルはリソースであるため、すべてのリソースに適用されるものと同じスコープ規則に従います。 つまり、スタイルを宣言する場所は、スタイルを適用できる場所に影響するということです。 たとえば、アプリ定義の XAML ファイルのルート要素でスタイルを宣言すると、そのスタイルはアプリ内のどこでも使用できます。

<Application x:Class="IntroToStylingAndTemplating.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:IntroToStylingAndTemplating"
             StartupUri="WindowExplicitStyle.xaml">
    <Application.Resources>
        <ResourceDictionary>
            
            <Style x:Key="Header1" TargetType="TextBlock">
                <Setter Property="FontSize" Value="15" />
                <Setter Property="FontWeight" Value="ExtraBold" />
            </Style>
            
        </ResourceDictionary>
    </Application.Resources>
</Application>

スタイルをアプリの XAML ファイルのいずれかで宣言すると、そのスタイルはその XAML ファイルでのみ使用できます。 リソースのスコープ規則の詳細については、XAML リソースの概要に関するページを参照してください。

<Window x:Class="IntroToStylingAndTemplating.WindowSingleResource"
        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:IntroToStylingAndTemplating"
        mc:Ignorable="d"
        Title="WindowSingleResource" Height="450" Width="800">
    <Window.Resources>
        
        <Style x:Key="Header1" TargetType="TextBlock">
            <Setter Property="FontSize" Value="15" />
            <Setter Property="FontWeight" Value="ExtraBold" />
        </Style>
        
    </Window.Resources>
    <Grid />
</Window>

スタイルは、スタイルが適用される要素のプロパティを設定する <Setter> 子要素で構成されます。 上記の例では、TargetType 属性を使用して TextBlock の型に適用するようにスタイルが設定されていることに注意してください。 このスタイルは、FontSize15 に設定し、FontWeightExtraBold に設定します。 スタイルが変更するプロパティごとに <Setter> を追加します。

スタイルを暗黙的に適用する

Style は、一連のプロパティ値を複数の要素に適用する便利な方法です。 たとえば、次の TextBlock 要素と、ウィンドウでのその既定の外観について考えてみます。

<StackPanel>
    <TextBlock>My Pictures</TextBlock>
    <TextBlock>Check out my new pictures!</TextBlock>
</StackPanel>

スタイル サンプルのスクリーンショット (前)

TextBlock 要素に FontSizeFontFamilyなどのプロパティを直接設定することにより、既定の外観を変更できます。 ただし、TextBlock の要素でいくつかのプロパティを共有する場合は、次に示すように、XAML ファイルの Resources セクションに Style を作成できます。

<Window.Resources>
    <!--A Style that affects all TextBlocks-->
    <Style TargetType="TextBlock">
        <Setter Property="HorizontalAlignment" Value="Center" />
        <Setter Property="FontFamily" Value="Comic Sans MS"/>
        <Setter Property="FontSize" Value="14"/>
    </Style>
</Window.Resources>

スタイルの TargetTypeTextBlock 型に設定し、x:Key 属性を省略すると、そのスタイルにスコープ指定されているすべての TextBlock 要素 (通常、XAML ファイル自体) にスタイルが適用されます。

これにより、TextBlock 要素は次のように表示されます。

スタイル サンプルのスクリーンショット (基本スタイル)

スタイルを明示的に適用する

値が含まれる x:Key 属性をスタイルに追加すると、そのスタイルは TargetType のすべての要素に暗黙的に適用されなくなります。 スタイルを明示的に参照する要素だけに、スタイルが適用されます。

次に示すのは、前のセクションのスタイルですが、x:Key 属性を使用して宣言されています。

<Window.Resources>
    <Style x:Key="TitleText" TargetType="TextBlock">
        <Setter Property="HorizontalAlignment" Value="Center" />
        <Setter Property="FontFamily" Value="Comic Sans MS"/>
        <Setter Property="FontSize" Value="14"/>
    </Style>
</Window.Resources>

スタイルを適用するには、次に示すように、StaticResource markup extension を使用して、要素の Style プロパティを x:Key 値に設定します。

<StackPanel>
    <TextBlock Style="{StaticResource TitleText}">My Pictures</TextBlock>
    <TextBlock>Check out my new pictures!</TextBlock>
</StackPanel>

最初の TextBlock 要素にはスタイルが適用され、2 番目の TextBlock 要素は未変更のままであることに注意してください。 前のセクションの暗黙的なスタイルは、x:Key 属性を宣言したスタイルに変更されました。つまり、このスタイルの影響を受ける要素は、スタイルを直接参照したものだけであるということです。

スタイル サンプルのスクリーンショット (textblock)

スタイルは明示的または暗黙的に適用されると、シールされて、変更できなくなります。 適用されているスタイルを変更する場合は、新しいスタイルを作成して、既存のスタイルを置き換えてください。 詳細については、IsSealed プロパティを参照してください。

カスタム ロジックに基づいて適用するスタイルを選択するオブジェクトを作成できます。 例については、StyleSelector クラスで提供されている例を参照してください。

プログラムを使用してスタイルを適用する

プログラムを使用して名前付きスタイルを要素に割り当てるには、リソース コレクションからスタイルを取得し、それを要素の Style プロパティに割り当てます。 リソース コレクションの項目は Object 型です。 そのため、取得したスタイルは、Style プロパティに割り当てる前に System.Windows.Style にキャストする必要があります。 たとえば、次のコードは、textblock1 という名前の TextBlock のスタイルを、定義されているスタイル TitleText に設定します。

textblock1.Style = (Style)Resources["TitleText"];
textblock1.Style = CType(Resources("TitleText"), Windows.Style)

スタイルを拡張する

たとえば、2 つの TextBlock 要素で、FontFamily や中央揃えされた HorizontalAlignment などのいくつかのプロパティ値を共有する必要がある場合があります。 しかし、同時に、My Pictures というテキストにいくつかの追加プロパティを持たせる必要もあります。 次に示すように、これは、最初のスタイルに基づく新しいスタイルを作成することで実現できます。

<Window.Resources>
    <!-- .... other resources .... -->

    <!--A Style that affects all TextBlocks-->
    <Style TargetType="TextBlock">
        <Setter Property="HorizontalAlignment" Value="Center" />
        <Setter Property="FontFamily" Value="Comic Sans MS"/>
        <Setter Property="FontSize" Value="14"/>
    </Style>
    
    <!--A Style that extends the previous TextBlock Style with an x:Key of TitleText-->
    <Style BasedOn="{StaticResource {x:Type TextBlock}}"
           TargetType="TextBlock"
           x:Key="TitleText">
        <Setter Property="FontSize" Value="26"/>
        <Setter Property="Foreground">
            <Setter.Value>
                <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                    <LinearGradientBrush.GradientStops>
                        <GradientStop Offset="0.0" Color="#90DDDD" />
                        <GradientStop Offset="1.0" Color="#5BFFFF" />
                    </LinearGradientBrush.GradientStops>
                </LinearGradientBrush>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

次に、スタイル TextBlockを .

<StackPanel>
    <TextBlock Style="{StaticResource TitleText}" Name="textblock1">My Pictures</TextBlock>
    <TextBlock>Check out my new pictures!</TextBlock>
</StackPanel>

例に示されているように、現在、この TextBlock スタイルは中央揃えされており、サイズ 26Comic Sans MS フォントを使用し、前景色は LinearGradientBrush に設定されています。 基本スタイルの FontSize 値がオーバーライドされていることに注意してください。 同じプロパティを指す SetterStyle に複数ある場合は、最後に宣言された Setter が優先されます。

TextBlock 要素が現在どのように表示されるかを次に示します。

スタイル設定された TextBlock

この TitleText スタイルは、BasedOn="{StaticResource {x:Type TextBlock}}" で参照される、TextBlock 型に対して作成されているスタイルを拡張します。 スタイルの x:Key を使用して x:Key を持つスタイルを拡張することもできます。 たとえば、Header1 という名前のスタイルがあり、そのスタイルを拡張する必要がある場合は、BasedOn="{StaticResource Header1}" を使用します。

TargetType プロパティと X:key 属性の関係

前述のように、スタイルに x:Key を割り当てずに TargetType プロパティを TextBlock に設定すると、すべての TextBlock 要素にそのスタイルが適用されます。 ここでは、x:Key は暗黙的に {x:Type TextBlock} に設定されます。 これは、x:Key 値を {x:Type TextBlock} 以外の値に明示的に設定すると、Style はすべての TextBlock 要素には自動的に適用されないことを意味します。 代わりに、(x:Key の値を使用して) スタイルを TextBlock 要素に明示的に適用する必要があります。 スタイルがリソース セクションにあり、スタイルに TargetType プロパティを設定していない場合は、x:Key 属性を設定する必要があります。

TargetType プロパティは、x:Key の既定値を提供するだけでなく、セッター プロパティが適用される型を指定します。 TargetType を指定しない場合は、Property="ClassName.Property" の構文を使用して、Setter オブジェクト内のプロパティをクラス名で修飾する必要があります。 たとえば、Property="FontSize" を設定するのではなく、Property"TextBlock.FontSize" または "Control.FontSize" に設定する必要があります。

また、多くの WPF コントロールは、その他の WPF コントロールの組み合わせで構成されていることに注意してください。 型のすべてのコントロールに適用されるスタイルを作成する場合、予期しない結果になる可能性があります。 たとえば、Window 内の TextBlock 型を対象とするスタイルを作成すると、TextBlock が別のコントロール (ListBoxなど) の一部であったとしても、ウィンドウ内のすべての TextBlock コントロールにそのスタイルが適用されます。

関連項目