XAML スタイル

XAML フレームワークを使って、さまざまな方法でアプリの外観をカスタマイズできます。 スタイルを使うと、コントロールのプロパティに値を設定し、その設定を再利用することで、複数のコントロールの外観を統一できます。

WinUI とスタイル

WinUI 2.2 以降、Microsoft はその UI コンポーネント全般に Windows UI ライブラリ (WinUI) を使用して最新の視覚スタイルを提供してきました。 UI が最新のスタイルに更新されないことに気付いた場合は、最新の WinUI NuGet パッケージに更新してください。

WinUI 2.6 以降では、ほとんどのコントロールに新しいスタイルが導入され、また、必要に応じて以前のコントロール スタイルに戻すことができる新しいバージョン管理システムが採用されています。 新しいスタイルの方が Windows の設計方針とも相性が良いため、Microsoft としては、そちらを使用することを推奨しています。 ただし、新しいスタイルが実際のシナリオにそぐわない場合は、以前のバージョンを引き続き利用することができます。

スタイルのバージョンは、WinUI バージョン 2 を使用するときに Application.Resources に追加した XamlControlsResourcesControlsResourcesVersion プロパティを選択することで変更できます。 ControlsResourcesVersion の既定値は列挙型の値 Version2 です。

この値を Version1 に設定すると、最新の WinUI バージョンで使用される新しいスタイルではなく、以前のスタイル バージョンが XamlControlsResources によって読み込まれます。 このプロパティを実行時に変更することはサポートされず、Visual Studio のホット リロード機能は正しく機能しませんが、アプリケーションのリビルド後は、コントロール スタイルの変更が反映されます。

<Application.Resources>
    <XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" 
                           ControlsResourcesVersion="Version1"/>
</Application.Resources>

スタイルの基本

スタイルを使うと、視覚的なプロパティの設定を、再利用可能なリソースとして抽出できます。 次の例は、BorderBrushBorderThickness、および Foreground プロパティを設定するスタイルを適用した 3 つのボタンを示しています。 スタイルを適用することで、これらのプロパティを各コントロールで個別に設定しなくて済み、また、コントロールに同じ外観を持たせることができます。

スタイルを適用した 3 つのボタンが横に並べて配置されているスクリーンショット。

スタイルは、XAML を使ってコントロールに対してインラインで定義するか、再利用可能なリソースとして定義できます。 リソースは、個々のページの XAML ファイル、App.xaml ファイル、別個のリソース ディクショナリ XAML ファイルのいずれかに定義します。 リソース ディクショナリ XAML ファイルはアプリ間で共有できます。また、単一のアプリで複数のリソース ディクショナリをマージすることも可能です。 リソースを定義する場所は、リソースが使われる範囲によって決まります。 ページ レベルのリソースは定義元のページでしか利用できません。 App.xaml とページ内の両方で同じキーが定義されている場合、ページ内のリソースが App.xaml 内のリソースよりも優先されます。 リソースが別個のリソース ディクショナリ ファイルで定義されている場合、そのスコープはリソース ディクショナリが参照される場所によって決まります。

Style の定義では、1 つの TargetType 属性と、1 つ以上の Setter 要素が必要になります。 TargetType 属性は、スタイルを適用する FrameworkElement 型を指定する文字列です。 TargetType の値では、Windows ランタイムか、参照先アセンブリ内で使用できるカスタム型で定義される FrameworkElement から派生した型を指定する必要があります。 適用しようとしているスタイルの TargetType 属性の指定内容と異なるコントロールやコントロールの型にスタイルを適用しようとすると、例外が発生します。

それぞれの Setter 要素に、PropertyValue が必要です。 この 2 つのプロパティは、それぞれ、その設定が適用されるコントロールのプロパティと、そのプロパティに対して設定される値を指定します。 Setter.Value は、属性構文またはプロパティ要素構文を使って設定できます。 次の XAML は前に示したボタンに適用されたスタイルを示しています。 この XAML では、最初の 2 つの Setter 要素に属性構文を使っていますが、BorderBrush プロパティ用の最後のSetter にはプロパティ要素構文を使っています。 この例では x:Key attribute 属性を使っていないため、スタイルはボタンに対して暗黙的に適用されます。 スタイルの暗黙的または明示的な適用については、次のセクションで説明します。

<Page.Resources>
    <Style TargetType="Button">
        <Setter Property="BorderThickness" Value="5" />
        <Setter Property="Foreground" Value="Black" />
        <Setter Property="BorderBrush" >
            <Setter.Value>
                <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                    <GradientStop Color="Yellow" Offset="0.0" />
                    <GradientStop Color="Red" Offset="0.25" />
                    <GradientStop Color="Blue" Offset="0.75" />
                    <GradientStop Color="LimeGreen" Offset="1.0" />
                </LinearGradientBrush>
            </Setter.Value>
        </Setter>
    </Style>
</Page.Resources>

<StackPanel Orientation="Horizontal">
    <Button Content="Button"/>
    <Button Content="Button"/>
    <Button Content="Button"/>
</StackPanel>

暗黙的または明示的なスタイルの適用

スタイルをリソースとして定義した場合、それをコントロールに適用するには 2 つの方法があります。

スタイルに x:Key 属性が含まれる場合、そのスタイルをコントロールに適用するには、コントロールの Style プロパティをキーで指定されたスタイルに設定する必要があります。 一方、x:Key attribute 属性を含まないスタイルは、ターゲットとなる型のすべてのコントロールに自動的に適用されます。それ以外の場合、これには明示的なスタイル設定がありません。

次の 2 つのボタンは、暗黙的なスタイルと明示的なスタイルを示しています。

暗黙的および明示的にスタイルが適用されたボタン。

この例では、最初のスタイルには x:Key 属性が含まれ、ターゲットとなる型は Button です。 最初のボタンの Style プロパティはこのキーに設定されているため、このスタイルは明示的に適用されます。 2 番目のスタイルは、ターゲットとなる型が Button で、スタイルに x:Key 属性が含まれないため、2 番目のボタンに暗黙的に適用されます。

<Page.Resources>
    <Style x:Key="PurpleStyle" TargetType="Button">
        <Setter Property="FontFamily" Value="Segoe UI"/>
        <Setter Property="FontSize" Value="14"/>
        <Setter Property="Foreground" Value="Purple"/>
    </Style>

    <Style TargetType="Button">
        <Setter Property="FontFamily" Value="Segoe UI"/>
        <Setter Property="FontSize" Value="14"/>
        <Setter Property="RenderTransform">
            <Setter.Value>
                <RotateTransform Angle="25"/>
            </Setter.Value>
        </Setter>
        <Setter Property="BorderBrush" Value="Green"/>
        <Setter Property="BorderThickness" Value="2"/>
        <Setter Property="Foreground" Value="Green"/>
    </Style>
</Page.Resources>

<Grid x:Name="LayoutRoot">
    <Button Content="Button" Style="{StaticResource PurpleStyle}"/>
    <Button Content="Button"/>
</Grid>

継承スタイルの使用

スタイルを管理しやすくし、スタイルの再利用を最適化するために、他のスタイルから継承するスタイルを作成できます。 継承したスタイルを作成するには、BasedOn プロパティを使います。 他のスタイルから継承するスタイルは、同じ型のコントロール、または基本スタイルのターゲットとなる型から派生したコントロールをターゲットとする必要があります。 たとえば、基本スタイルのターゲットが ContentControl である場合、このスタイルに基づくスタイルは、ContentControl、または ContentControl から派生した型 (ButtonScrollViewer など) をターゲットにできます。 継承スタイルに対して設定しない値は、基本スタイルから継承されます。 基本スタイルから値を変更するには、継承スタイルに値を設定して上書きします。 次の例は、同じ基本スタイルから継承したスタイルを持つ ButtonCheckBox を示しています。

継承スタイルを使ってスタイルを適用したボタン。

基本スタイルは ContentControl をターゲットとし、Height プロパティと Width プロパティを設定します。 このスタイルに基づくスタイルは、ContentControl から派生した CheckBoxButton をターゲットとします。 各継承スタイルでは、BorderBrush プロパティと Foreground プロパティに異なる色を設定しています (通常は 、CheckBox の周囲に罫線を配置しません。ここでは、スタイルの効果を示します。

<Page.Resources>
    <Style x:Key="BasicStyle" TargetType="ContentControl">
        <Setter Property="Width" Value="130" />
        <Setter Property="Height" Value="30" />
    </Style>

    <Style x:Key="ButtonStyle" TargetType="Button"
           BasedOn="{StaticResource BasicStyle}">
        <Setter Property="BorderBrush" Value="Orange" />
        <Setter Property="BorderThickness" Value="2" />
        <Setter Property="Foreground" Value="Red" />
    </Style>

    <Style x:Key="CheckBoxStyle" TargetType="CheckBox"
           BasedOn="{StaticResource BasicStyle}">
        <Setter Property="BorderBrush" Value="Blue" />
        <Setter Property="BorderThickness" Value="2" />
        <Setter Property="Foreground" Value="Green" />
    </Style>
</Page.Resources>

<StackPanel>
    <Button Content="Button" Style="{StaticResource ButtonStyle}" Margin="0,10"/>
    <CheckBox Content="CheckBox" Style="{StaticResource CheckBoxStyle}"/>
</StackPanel>

ツールを使ってスタイルを簡単に操作

コントロールにスタイルをすばやく適用する方法の 1 つは、Microsoft Visual Studio の XAML デザイン サーフェイスでコントロールを右クリックし、 [スタイルの編集] または [テンプレートの編集] (右クリックしたコントロールによって異なる) をクリックすることです。 その後、 [リソースの適用] をクリックして既にあるスタイルを適用するか、または [空アイテムの作成] をクリックして新しいスタイルを定義できます。 空のスタイルを作成する場合は、ページ、App.xaml ファイル、または別のリソース ディクショナリにそのスタイルを定義できます。

軽量なスタイル設定

システム ブラシのオーバーライドは一般にアプリ レベルまたはページ レベルで行われます。いずれの場合も、色のオーバーライドはそのブラシを参照するすべてのコントロールに影響します。また、XAML では多くのコントロールが同じシステム ブラシを参照できます。

2 つのボタンのスクリーンショット: 1 つは静止状態で、もう 1 つは軽量なスタイル設定が適用されています。

<Page.Resources>
    <ResourceDictionary>
        <ResourceDictionary.ThemeDictionaries>
            <ResourceDictionary x:Key="Light">
                 <SolidColorBrush x:Key="ButtonBackground" Color="Transparent"/>
                 <SolidColorBrush x:Key="ButtonForeground" Color="MediumSlateBlue"/>
                 <SolidColorBrush x:Key="ButtonBorderBrush" Color="MediumSlateBlue"/>
            </ResourceDictionary>
        </ResourceDictionary.ThemeDictionaries>
    </ResourceDictionary>
</Page.Resources>

PointerOver (マウスがボタンの上に置かれている)、PointerPressed (ボタンが押された)、Disabled (ボタンが有効でない) などの状態に使用します。 これらの末尾は、元の Lightweight スタイル名 ( ButtonBackgroundPointerOverButtonForegroundPressedButtonBorderBrushDisabled など) に追加されます。これらのブラシも変更すると、コントロールがアプリのテーマに一貫して色付けされます。

これらのブラシを配置すると、App.Resources レベルでオーバーライドし、(単一ページではなく) アプリ全体のすべてのボタンを変更します。

コントロールごとのスタイル設定

他のケースでは、コントロールの他のバージョンを変更することなく、1 つのページ上の単一のコントロールを特定の方法で表示するように変更することが望ましい方法です。

スタイルを適用された 3 つのボタンを上下に積み重ねて配列したスクリーンショット。

<CheckBox Content="Normal CheckBox" Margin="5"/>
<CheckBox Content="Special CheckBox" Margin="5">
    <CheckBox.Resources>
        <ResourceDictionary>
            <ResourceDictionary.ThemeDictionaries>
                <ResourceDictionary x:Key="Light">
                    <SolidColorBrush x:Key="CheckBoxForegroundUnchecked"
                        Color="Purple"/>
                    <SolidColorBrush x:Key="CheckBoxForegroundChecked"
                        Color="Purple"/>
                    <SolidColorBrush x:Key="CheckBoxCheckGlyphForegroundChecked"
                        Color="White"/>
                    <SolidColorBrush x:Key="CheckBoxCheckBackgroundStrokeChecked"  
                        Color="Purple"/>
                    <SolidColorBrush x:Key="CheckBoxCheckBackgroundFillChecked"
                        Color="Purple"/>
                </ResourceDictionary>
            </ResourceDictionary.ThemeDictionaries>
        </ResourceDictionary>
    </CheckBox.Resources>
</CheckBox>
<CheckBox Content="Normal CheckBox" Margin="5"/>

これは、そのコントロールが存在していたページ上の 1 つの "Special CheckBox" にのみ影響します。

カスタム コントロール

Microsoft の組み込みのコントロールと視覚的または機能的に調和したカスタム コントロールを独自に作成するときは、暗黙的なスタイル設定リソースと軽量スタイル設定リソースを使用してカスタム コンテンツを定義することを検討してください。 リソースを直接使用するか、またはリソースの別名を新たに作成することができます。

コントロール リソースを直接使用する

たとえば、ボタンに似たコントロールを作成する場合、次のように、コントロールにボタン リソースを直接参照させることができます。

<Style TargetType="local:MyCustomControl">
  <Setter Property="Background" Value="{ThemeResource ButtonBackground}" />
  <Setter Property="BorderBrush" Value="{ThemeResource ButtonBorderBrush}" />
</Style>

コントロール リソースの別名を新たに作成する

また、独自のリソースを作成したい場合は、それらのカスタム名を、Microsoft の既定の軽量スタイル設定リソースに対する別名として設定する必要があります。

たとえば、カスタム コントロールのスタイルに、特殊なリソース定義を設定するとしましょう。

<Style TargetType="local:MyCustomControl">
  <Setter Property="Background" Value="{ThemeResource MyCustomControlBackground}" />
  <Setter Property="BorderBrush" Value="{ThemeResource MyCustomControlBorderBrush}"/>
</Style>

この場合、リソース ディクショナリまたはメイン定義内で、軽量スタイル設定リソースをカスタム リソースにフックすることになります。

<ResourceDictionary.ThemeDictionaries>
    <ResourceDictionary x:Key="Default">
        <StaticResource x:Key="MyCustomControlBackground" ResourceKey="ButtonBackground" />
        <StaticResource x:Key="MyCustomControlBorderBrush" ResourceKey="ButtonBorderBrush" />
    </ResourceDictionary>        
    <ResourceDictionary x:Key="Light">
        <StaticResource x:Key="MyCustomControlBackground" ResourceKey="ButtonBackground" />
        <StaticResource x:Key="MyCustomControlBorderBrush" ResourceKey="ButtonBorderBrush" />
    </ResourceDictionary>
    <ResourceDictionary x:Key="HighContrast">
        <StaticResource x:Key="MyCustomControlBackground" ResourceKey="ButtonBackground" />
        <StaticResource x:Key="MyCustomControlBorderBrush" ResourceKey="ButtonBorderBrush" />
    </ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>

3 種類のテーマ変更 (DefaultLightHighContrast) を適切に処理するためには、ThemeDictionary を 3 回複製して使用する必要があります。

注意事項

軽量スタイル設定リソースを新しい別名に割り当てると同時に、軽量スタイル設定リソースを再定義する場合、リソース ルックアップが正しい順序で行われないと、カスタマイズが適用されないことがあります。 たとえば、MyCustomControlBackground が見つかる前に検索される場所で ButtonBackground をオーバーライドした場合、そのオーバーライドは適用されません。

コントロールの再スタイル設定を避ける

Windows UI ライブラリ 2.2 以降には、WinUI とシステム コントロールの両方に使用される新しいスタイルとテンプレートが含まれています。

Microsoft が提供する最新の視覚スタイルに追随する一番の方法は、最新の WinUI 2 パッケージを使用し、カスタムのスタイルとテンプレート (再テンプレート化ともいいます) を避けることです。 それでもスタイルは、アプリ内のコントロール全体に一貫した方法で一連の値を適用する有効な手段です。 使用する際は、必ず最新のスタイルをベースにするようにしてください。

WinUI スタイル (Windows.UI.Xaml.Controls 名前空間) を使用するシステム コントロールの場合、BasedOn="{StaticResource Default<ControlName>Style}" を設定します (<ControlName> はコントロールの名前)。 次に例を示します。

<Style TargetType="TextBox" BasedOn="{StaticResource DefaultTextBoxStyle}">
    <Setter Property="Foreground" Value="Blue"/>
</Style>

WinUI 2 コントロール (Microsoft.UI.Xaml.Controls 名前空間) では、既定のスタイルがメタデータに定義されるため、BasedOn は省略します。

派生コントロール

既存の XAML コントロールからカスタム コントロールを派生させた場合、WinUI 2 スタイルが既定では適用されません。 WinUI 2 スタイルを適用するには、次のようにします。

  • TargetType がカスタム コントロールに設定された新しいスタイルを作成します。
  • そのスタイルのベースとして、派生元のコントロールの既定のスタイルを使用します。

この場合の一般的なシナリオの 1 つは、ContentDialog から新しいコントロールを派生させることです。 この例は、DefaultContentDialogStyle をカスタム ダイアログに適用する新しいスタイルを作成する方法を示しています。

<ContentDialog
    x:Class="ExampleApp.SignInContentDialog"
    ... >

    <ContentDialog.Resources>
        <Style TargetType="local:SignInContentDialog" BasedOn="{StaticResource DefaultContentDialogStyle}"/>
        ...
    </ContentDialog.Resources> 
    <!-- CONTENT -->
</ContentDialog>        

テンプレート プロパティ

スタイル setter は、ControlTemplate プロパティに使うことができ、実際に、一般的な XAML スタイルとアプリの XAML リソースの主要な部分を構成しています。 詳しくは、「コントロール テンプレート」をご覧ください。