ResourceDictionary と XAML リソースの参照
XAML を使用して、アプリの UI またはリソースを定義できます。 リソースは、通常、複数回使用することが予想されるオブジェクトの定義です。 後で XAML リソースを参照するには、その名前のように機能するリソースのキーを指定します。 アプリ全体またはアプリ内の任意の XAML ページからリソースを参照できます。 リソースは、Windows ランタイム XAML の ResourceDictionary 要素を使用して定義できます。 その後、StaticResource マークアップ拡張機能または ThemeResource マークアップ拡張機能を使用して、リソースを参照できます。
XAML リソースとして最も頻繁に宣言する XAML 要素には、Style、ControlTemplate、アニメーション コンポーネント、Brush サブクラスなどがあります。 ここでは、ResourceDictionary リソースとキー付きリソースを定義する方法と、XAML リソースをアプリまたはアプリ パッケージの一部として定義する他のリソースとどのように関連するかを説明します。 また、MergedDictionaries や ThemeDictionaries などのリソース ディクショナリの高度な機能についても説明します。
前提条件
XAML マークアップをしっかりと理解している。 「XAML の概要」を読むことをお勧めします。
XAML リソースの定義と使用
XAML リソースは、マークアップから複数回参照されるオブジェクトです。 リソースは ResourceDictionary で定義されます。通常は、別のファイルまたはマークアップ ページの上部に定義されます。次のようになります。
<Page
x:Class="MSDNSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<x:String x:Key="greeting">Hello world</x:String>
<x:String x:Key="goodbye">Goodbye world</x:String>
</Page.Resources>
<TextBlock Text="{StaticResource greeting}" Foreground="Gray" VerticalAlignment="Center"/>
</Page>
次の点に注意してください。
<Page.Resources>…</Page.Resources>
- リソース ディクショナリを定義します。<x:String>
- キー「greeting」を使用してリソースを定義します。{StaticResource greeting}
- TextBlock の Text プロパティに割り当てられた、キー "greeting" を持つリソースを検索します。
注 ResourceDictionary に関連する概念を、リソース ビルド アクション、リソース (.resw) ファイル、またはアプリ パッケージを生成するコード プロジェクトの構築のコンテキストで説明されるその他の "リソース" と混同しないでください。
リソースは文字列である必要はありません。スタイル、テンプレート、ブラシ、色など、任意の共有可能なオブジェクトを指定できます。 ただし、コントロール、図形、およびその他の FrameworkElement は共有できないため、再利用可能なリソースとして宣言することはできません。 共有の詳細については、このトピックで後述する「XAML リソースを共有可能にする必要がある」セクションを参照してください。
ここでは、ブラシと文字列の両方がリソースとして宣言され、ページ内のコントロールによって使用されます。
<Page
x:Class="SpiderMSDN.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<SolidColorBrush x:Key="myFavoriteColor" Color="green"/>
<x:String x:Key="greeting">Hello world</x:String>
</Page.Resources>
<TextBlock Foreground="{StaticResource myFavoriteColor}" Text="{StaticResource greeting}" VerticalAlignment="Top"/>
<Button Foreground="{StaticResource myFavoriteColor}" Content="{StaticResource greeting}" VerticalAlignment="Center"/>
</Page>
すべてのリソースにキーが必要です。 通常、そのキーは x:Key="myString"
で定義された文字列です。 ただし、キーを指定する方法はいくつかあります。
- Style と ControlTemplate には TargetType が必要であり、x:Key が指定されていない場合は TargetType をキーとして使用します。 この場合、キーは実際の Type オブジェクトであり、文字列ではありません。 (次の例を参照してください)
- TargetType を持つ DataTemplate リソースでは、x:Key が指定されていない場合、TargetType がキーとして使用されます。 この場合、キーは実際の Type オブジェクトであり、文字列ではありません。
- x:Key の代わりに x:Name が使われています。 ただし、x:Name では、リソースの分離コード フィールドも生成されます。 その結果、ページが読み込まれるときにフィールドを初期化する必要があるため、x:Name は x:Key よりも効率が低くなります。
StaticResource マークアップ拡張機能は、文字列名 (x:Key または x:Name) のみを使用してリソースを取得できます。 ただし、Styleプロパティと ContentTemplate プロパティまたは ItemTemplate プロパティを設定していないコントロールに使うスタイルとテンプレート を決定する際に、XAML フレームワークは暗黙的なスタイル リソース (x:Key または x:Name ではなく TargetTypeを使うリソース) も探します。
ここでは、Style には typeof(Button) の暗黙的なキーがあり、ページの下部にある Button では Style プロパティが指定されていないため、typeof(Button) のキーを持つスタイルが検索されます。
<Page
x:Class="MSDNSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<Style TargetType="Button">
<Setter Property="Background" Value="Red"/>
</Style>
</Page.Resources>
<Grid>
<!-- This button will have a red background. -->
<Button Content="Button" Height="100" VerticalAlignment="Center" Width="100"/>
</Grid>
</Page>
暗黙的なスタイルとそのしくみの詳細については、「コントロールとコントロール テンプレートのスタイル設定」を参照してください。
コードでリソースを検索する
その他のディクショナリと同様に、リソース ディクショナリのメンバーにアクセスします。
警告
コード内でこのリソース検索を実行すると、Page.Resources
ディクショナリ内のリソースだけが検索されます。 StaticResource マークアップ拡張とは異なり、最初のディクショナリでリソースが見つからない場合に、コードは Application.Resources
ディクショナリにフォールバックしません。
この例では、ページのリソース ディクショナリから redButtonStyle
リソースを取得する方法を示します。
<Page
x:Class="MSDNSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<Style TargetType="Button" x:Key="redButtonStyle">
<Setter Property="Background" Value="red"/>
</Style>
</Page.Resources>
</Page>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
Style redButtonStyle = (Style)this.Resources["redButtonStyle"];
}
}
MainPage::MainPage()
{
InitializeComponent();
Windows::UI::Xaml::Style style = Resources().TryLookup(winrt::box_value(L"redButtonStyle")).as<Windows::UI::Xaml::Style>();
}
コードからアプリ全体のリソースを検索するには、次に示すように、Application.Current.Resources を使用してアプリのリソース ディクショナリを取得します。
<Application
x:Class="MSDNSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:SpiderMSDN">
<Application.Resources>
<Style TargetType="Button" x:Key="appButtonStyle">
<Setter Property="Background" Value="red"/>
</Style>
</Application.Resources>
</Application>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
Style appButtonStyle = (Style)Application.Current.Resources["appButtonStyle"];
}
}
MainPage::MainPage()
{
InitializeComponent();
Windows::UI::Xaml::Style style = Application::Current().Resources()
.TryLookup(winrt::box_value(L"appButtonStyle"))
.as<Windows::UI::Xaml::Style>();
}
コードでアプリケーション リソースを追加することもできます。
その場合は、次の 2 つの点に注意する必要があります。
- まず、ページでリソースの使用を試みる前に、リソースを追加する必要があります。
- 次に、アプリのコンストラクターにリソースを追加することはできません。
次のように Application.OnLaunched メソッドにリソースを追加すると、両方の問題を回避できます。
// App.xaml.cs
sealed partial class App : Application
{
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame == null)
{
SolidColorBrush brush = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 0, 255, 0)); // green
this.Resources["brush"] = brush;
// … Other code that VS generates for you …
}
}
}
// App.cpp
void App::OnLaunched(LaunchActivatedEventArgs const& e)
{
Frame rootFrame{ nullptr };
auto content = Window::Current().Content();
if (content)
{
rootFrame = content.try_as<Frame>();
}
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == nullptr)
{
Windows::UI::Xaml::Media::SolidColorBrush brush{ Windows::UI::ColorHelper::FromArgb(255, 0, 255, 0) };
Resources().Insert(winrt::box_value(L"brush"), winrt::box_value(brush));
// … Other code that VS generates for you …
すべての FrameworkElement は ResourceDictionary を持つことができる
FrameworkElement は、コントロールが継承する基本クラスであり、Resources プロパティを持っています。 そのため、任意の FrameworkElement にローカル リソース ディクショナリを追加できます。
ここでは、Page と Border の両方にリソース ディクショナリがあり、どちらも "greeting" というリソースを持っています。 "textBlock2" という名前の TextBlock は Border 内にあるため、そのリソース検索はまず Border のリソースを検索した後、Page のリソース、次に Application のリソースの順に検索します。 TextBlock は "Hola mundo" と読み取ります。
コードからその要素のリソースにアクセスするには、その要素の Resources プロパティを使います。 XAML ではなくコード内の FrameworkElement のリソースにアクセスすると、親要素のディクショナリではなくそのディクショナリのみ検索されます。
<Page
x:Class="MSDNSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<x:String x:Key="greeting">Hello world</x:String>
</Page.Resources>
<StackPanel>
<!-- Displays "Hello world" -->
<TextBlock x:Name="textBlock1" Text="{StaticResource greeting}"/>
<Border x:Name="border">
<Border.Resources>
<x:String x:Key="greeting">Hola mundo</x:String>
</Border.Resources>
<!-- Displays "Hola mundo" -->
<TextBlock x:Name="textBlock2" Text="{StaticResource greeting}"/>
</Border>
<!-- Displays "Hola mundo", set in code. -->
<TextBlock x:Name="textBlock3"/>
</StackPanel>
</Page>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
textBlock3.Text = (string)border.Resources["greeting"];
}
}
MainPage::MainPage()
{
InitializeComponent();
textBlock3().Text(unbox_value<hstring>(border().Resources().TryLookup(winrt::box_value(L"greeting"))));
}
マージされたリソース ディクショナリ
マージされたリソース ディクショナリは、1 つのリソース ディクショナリを別のリソース ディクショナリ (通常は別のファイル) に結合します。
ヒント Microsoft Visual Studio でリソース ディクショナリ ファイルを作成するには、[プロジェクト] メニューの [追加] > [新しい項目] > [リソース ディクショナリ] オプション を使います。
ここでは、Dictionary1.xaml という別の XAML ファイルでリソース ディクショナリを定義します。
<!-- Dictionary1.xaml -->
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MSDNSample">
<SolidColorBrush x:Key="brush" Color="Red"/>
</ResourceDictionary>
そのディクショナリを使うには、ページのディクショナリと結合します。
<Page
x:Class="MSDNSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary1.xaml"/>
</ResourceDictionary.MergedDictionaries>
<x:String x:Key="greeting">Hello world</x:String>
</ResourceDictionary>
</Page.Resources>
<TextBlock Foreground="{StaticResource brush}" Text="{StaticResource greeting}" VerticalAlignment="Center"/>
</Page>
この例では、次の処理が行われます。 <Page.Resources>
で、<ResourceDictionary>
を宣言します。 リソースを <Page.Resources>
に追加すると、XAML フレームワークによりリソース ディクショナリが暗黙的に自動作成されますが、この場合に必要なのは通常のリソース ディクショナリではなく、結合されたディクショナリを含むリソース ディクショナリです。
したがって、<ResourceDictionary>
を宣言してから <ResourceDictionary.MergedDictionaries>
コレクションに追加します。 これらのエントリのそれぞれは、フォーム <ResourceDictionary Source="Dictionary1.xaml"/>
を取ります。 複数のディクショナリを追加するには、最初のエントリの後に <ResourceDictionary Source="Dictionary2.xaml"/>
エントリを追加するだけです。
<ResourceDictionary.MergedDictionaries>…</ResourceDictionary.MergedDictionaries>
の後、必要に応じて、メイン ディクショナリに追加のリソースを配置できます。 通常のディクショナリと同様に、マージされたディクショナリのリソースを使用します。 上の例では、{StaticResource brush}
は子ディクショナリまたはマージされたディクショナリ (Dictionary1.xaml) でリソースを検索し、{StaticResource greeting}
はメイン ページ ディクショナリでそのリソースを検索します。
リソース検索シーケンスでは、MergedDictionaries ディクショナリは、その ResourceDictionary の他のすべてのキー付きリソースのチェックの後にのみチェックされます。 そのレベルを検索すると、参照はマージされたディクショナリに到達し、MergedDictionaries の各項目がチェックされます。 複数のマージされたディクショナリが存在する場合、これらのディクショナリは、MergedDictionaries プロパティで宣言されている順序の逆の順序でチェックされます。 次の例では、Dictionary2.xaml と Dictionary1.xaml の両方で同じキーが宣言されている場合、最初に Dictionary2.xaml のキーが使用されます。これは MergedDictionaries セットの最後であるためです。
<Page
x:Class="MSDNSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary1.xaml"/>
<ResourceDictionary Source="Dictionary2.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Page.Resources>
<TextBlock Foreground="{StaticResource brush}" Text="greetings!" VerticalAlignment="Center"/>
</Page>
1 つの ResourceDictionary のスコープ内で、ディクショナリはキーの一意性のためにチェックされます。 ただし、そのスコープは、異なる MergedDictionaries ファイル内の異なる項目にまたがって拡張されることはありません。
検索シーケンスの組み合わせと、マージされたディクショナリ スコープ間での一意のキーの強制の欠如を使用して、ResourceDictionary リソースのフォールバック値シーケンスを作成できます。 たとえば、アプリの状態とユーザー設定データに同期するリソース ディクショナリを使用して、シーケンス内の最後にマージされたリソース ディクショナリに特定のブラシの色のユーザー設定を格納できます。 ただし、ユーザー設定がまだ存在しない場合は、最初の MergedDictionaries ファイル内の ResourceDictionary リソースに同じキー文字列を定義し、フォールバック値として使用できます。 プライマリ リソース ディクショナリで指定した値は、マージされたディクショナリがチェックされる前に常にチェックされるので、フォールバック手法を使用する場合は、プライマリ リソース ディクショナリでそのリソースを定義しないでください。
テーマ リソースとテーマ ディクショナリ
ThemeResource は StaticResource に似ていますが、テーマが変更されるとリソース検索が再評価されます。
この例では、TextBlock の前景を現在のテーマの値に設定します。
<TextBlock Text="hello world" Foreground="{ThemeResource FocusVisualWhiteStrokeThemeBrush}" VerticalAlignment="Center"/>
テーマ ディクショナリは、ユーザーが現在自分のデバイスで使用しているテーマによって異なるリソースを保持する、特殊な種類のマージされたディクショナリです。 たとえば、"明るい" テーマでは白のカラー ブラシを使用し、"濃色" テーマでは濃色ブラシを使用する場合があります。 ブラシは解決先のリソースを変更しますが、それ以外の場合は、ブラシをリソースとして使用するコントロールの構成が同じになる可能性があります。 MergeedDictionaries をプロパティとして使用して項目をメインディクショナリにマージするのではなく、独自のテンプレートとスタイルでテーマ切り替え動作を再現するには、ThemeDictionaries プロパティを使用します。
ThemeDictionaries 内の各 ResourceDictionary 要素には、x:Key 値が必要です。 この値は、関連するテーマ ("Default"、"Dark"、"Light"、"HighContrast" など) に名前を付けた文字列です。 通常は、Dictionary1
と Dictionary2
は同じ名前で値が異なるリソースを定義します。
ここでは、明るいテーマには赤いテキストを、濃色テーマには青いテキストを使用します。
<!-- Dictionary1.xaml -->
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MSDNSample">
<SolidColorBrush x:Key="brush" Color="Red"/>
</ResourceDictionary>
<!-- Dictionary2.xaml -->
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MSDNSample">
<SolidColorBrush x:Key="brush" Color="blue"/>
</ResourceDictionary>
この例では、TextBlock の前景を現在のテーマの値に設定します。
<Page
x:Class="MSDNSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary Source="Dictionary1.xaml" x:Key="Light"/>
<ResourceDictionary Source="Dictionary2.xaml" x:Key="Dark"/>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Page.Resources>
<TextBlock Foreground="{StaticResource brush}" Text="hello world" VerticalAlignment="Center"/>
</Page>
テーマ ディクショナリの場合、リソース検索に使用されるアクティブなディクショナリは、ThemeResource マークアップ拡張機能を使用して参照を行い、システムがテーマの変更を検出するたびに、動的に変更されます。 システムによって実行される検索ビヘイビアーは、アクティブなテーマを特定のテーマ ディクショナリの x:Key にマッピングすることによって行われます。
デフォルトの XAML デザイン リソースでテーマ ディクショナリが構造化されている方法を調べると便利です。このリソースは、Windows ランタイムが既定ではコントロールに使用するテンプレートと並列化されます。 テキスト エディターか IDE を使用して、\(Program Files)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\<SDK version>\Generic の XAML ファイルを開きます。 最初に generic.xaml でテーマ ディクショナリを定義する方法と、各テーマ ディクショナリで同じキーを定義する方法に注意してください。 その後、このような各キーは、テーマ ディクショナリの外部にあり、XAML で後で定義されるさまざまなキー要素のコンポジションの要素によって参照されます。 デフォルトのコントロール テンプレートではなく、テーマ リソースと追加のテンプレートのみを含むデザイン用の個別の themeresources.xaml ファイルもあります。 テーマ領域は、generic.xaml に表示される内容の複製です。
XAML デザイン ツールを使用してスタイルとテンプレートのコピーを編集する場合、デザイン ツールは XAML デザイン リソース ディクショナリからセクションを抽出し、アプリとプロジェクトの一部である XAML ディクショナリ要素のローカル コピーとして配置します。
詳しい情報や、自分のアプリで利用できるテーマ固有のリソースとシステム リソースの一覧については、「XAML テーマ リソース」をご覧ください。
XAML リソース参照の検索ビヘイビアー
検索ビヘイビアーは、XAML リソース システムが XAML リソースを検索する方法を説明する用語です。 検索は、キーがアプリの XAML 内のどこかから XAML リソース参照として参照されるときに発生します。 まず、リソース システムは、スコープに基づいてリソースの存在をチェックする予測可能な動作を備えています。 リソースが初期スコープに見つからない場合、スコープは拡張されます。 検索ビヘイビアーは、XAML リソースがアプリまたはシステムによって定義される可能性がある場所とスコープ全体で継続されます。 可能なすべてのリソース検索の試行が失敗すると、多くの場合、エラーが発生します。 通常、開発プロセス中にこれらのエラーをなくす可能性があります。
XAML リソース検索の参照ビヘイビアーは、実際の使用状況が適用されるオブジェクトと、独自の Resources プロパティから始まります。 ResourceDictionary が存在する場合、その ResourceDictionary は、要求されたキーを持つアイテムに対してチェックされます。 この第 1 レベルの検索は、通常は同じオブジェクト上のリソースを定義して参照しないため、ほとんど関係ありません。 実際、 Resources プロパティは、多くの場合、ここには存在しません。 XAML リソース参照は、XAML のほぼすべての場所から行うことができます。FrameworkElement サブクラスのプロパティに限定されるわけではありません。
検索シーケンスは、アプリのランタイム オブジェクト ツリー内の次の親オブジェクトをチェックします。 FrameworkElement.Resources が存在し、ResourceDictionary を保持している場合は、指定されたキー文字列を持つディクショナリ項目が要求されます。 リソースが見つかった場合、検索シーケンスが停止し、参照が行われた場所にオブジェクトが提供されます。 それ以外の場合、検索ビヘイビアーはオブジェクト ツリー ルートに向かって次の親レベルに進みます。 検索は、XAML のルート要素に到達するまで再帰的に上向きに続き、可能なすべての即時リソースの場所の検索を使い果たします。
Note
このリソース検索動作と共に XAML マークアップ スタイルの規則も利用するために、すべての即時リソースをページのルート レベルに定義するのは一般的なやり方です。
要求されたリソースが即時リソースで見つからない場合、次の検索手順は Application.Resources プロパティをチェックすることです。 Application.Resources は、複数のページによって参照されるアプリ固有のリソースをアプリのナビゲーション構造に配置するのに最適な場所です。
重要
ResourceDictionary にリソースが追加される順序は、それらが適用される順序に影響します。 XamlControlsResources
ディクショナリによって多くの既定リソース キーがオーバーライドされるため、アプリ内の他のカスタム スタイルやリソースがオーバーライドされないように、まずこのディクショナリを Application.Resources
に追加する必要があります。
コントロール テンプレートには、参照検索内の別の場所 (テーマ ディクショナリ) があります。 テーマ ディクショナリは、ルートとして ResourceDictionary 要素を持つ 1 つの XAML ファイルです。 テーマ ディクショナリは、Application.Resources からマージされたディクショナリである可能性があります。 テーマ ディクショナリは、テンプレート化されたカスタム コントロールのコントロール固有のテーマ ディクショナリである場合もあります。
最後に、プラットフォーム リソースに対するリソース検索があります。 プラットフォーム リソースには、システム UI テーマごとに定義され、Windows ランタイム アプリで UI に使用するすべてのコントロールのデフォルトの外観を定義するコントロール テンプレートが含まれます。 プラットフォーム リソースには、システム全体の外観とテーマに関連する一連の名前付きリソースも含まれます。 これらのリソースは技術的には MergedDictionaries 項目であるため、アプリの読み込み後に XAML またはコードから検索できます。 たとえば、システム テーマ リソースには、"SystemColorWindowTextColor" という名前のリソースが含まれます。このリソースは、アプリのテキストの色と、オペレーティング システムとユーザー設定に由来するシステム ウィンドウのテキストの色に一致する色定義を提供します。 アプリのその他の XAML スタイルでこのスタイルを参照することも、コードでリソース検索値を取得することもできます (この例では Color にキャストします)。
詳しい情報や、XAML を使う Windows アプリで利用できるテーマ固有のリソースとシステム リソースの一覧については、「XAML テーマ リソース」をご覧ください。
要求されたキーがこれらの場所でまだ見つからない場合は、XAML 解析エラー/例外が発生します。 特定の状況では、XAML 解析例外は、XAML マークアップ コンパイル アクションまたは XAML デザイン環境によって検出されない実行時例外である可能性があります。
リソース ディクショナリの階層化された検索ビヘイビアーのため、各リソースが異なるレベルで定義されている限り、キーと同じ文字列値を持つ複数のリソース項目を意図的に定義できます。 言い換えると、キーは特定の ResourceDictionary 内で一意である必要がありますが、一意性の要件は検索ビヘイビアー シーケンス全体に拡張されません。 検索中に、正常に取得された最初のオブジェクトのみが XAML リソース参照に使用され、検索が停止します。 この動作を使用すると、アプリの XAML 内のさまざまな位置でキーによって同じ XAML リソースを要求できますが、XAML リソース参照の作成元のスコープとその特定の検索の動作に応じて、異なるリソースが返されます。
ResourceDictionary 内の参照を転送する
特定のリソース ディクショナリ内からの静的リソース参照は、キーで既に定義されたリソースを参照するひつ用があり、そのリソースは、リソース参照の前に既に辞書的に表示される必要があります。 前方参照は、XAML リソース参照では解決できません。 このため、別のリソース内から XAML リソース参照を使用する場合は、他のリソースによって使用されるリソースがリソース ディクショナリで最初に定義されるように、リソース ディクショナリ構造を設計する必要があります。
アプリ レベルで定義されたリソースは、即時リソースへの参照を作成できません。 これは、アプリ リソースが最初に (アプリが最初に開始されたとき、ナビゲーションページ コンテンツが読み込まれる前に) 処理されるため、前方参照を試みるのと同じです。 ただし、即時リソースはアプリ リソースへの参照を行うことができます。これは、前方参照の状況を回避するための便利な手法です。
XAML リソースは共有可能である必要がある
ResourceDictionary にオブジェクトを存在させるには、そのオブジェクトを共有できる必要があります。
アプリのオブジェクト ツリーが構築され、実行時に使用される場合、オブジェクトはツリー内の複数の場所に存在できないため、共有可能であることが必要です。 内部的には、リソース システムは、各 XAML リソースが要求されたときにアプリのオブジェクト グラフで使用するリソース値のコピーを作成します。
一般に、ResourceDictionary と Windows ランタイム XAML では、共有可能な使用のためにこれらのオブジェクトがサポートされています。
- スタイルとテンプレート (FrameworkTemplate から派生した Style とクラス)
- ブラシと色 (Brush および Color の値から派生したクラス)
- ストーリーボードを含むアニメーションの種類
- 変換 (GeneralTransform から派生したクラス)
- Matrix と Matrix3D
- ポイント値
- Thickness や CornerRadius などの他の UI 関連の構造
- XAML 固有のデータ型
必要な実装パターンに従う場合は、カスタム型を共有可能なリソースとして使用することもできます。 このようなクラスは、バッキング コード (または含めるランタイム コンポーネント) で定義し、XAML でリソースとしてインスタンス化します。 たとえば、データ バインディングのオブジェクト データ ソースと IValueConverter の実装があります。
カスタム型にはデフォルトのコンストラクターが必要です。これは、XAML パーサーがクラスをインスタンス化するために使用するためです。 リソースとして使用されるカスタム型は、UIElement を共有できないため、継承に UIElement クラスを含めることはできません (ランタイム アプリのオブジェクト グラフ内の 1 つの位置に存在する 1 つの UI 要素を常に表すことを意図しています)。
UserControl の使用スコープ
UserControl 要素には、定義スコープと使用スコープの固有の概念があるため、リソース検索ビヘイビアーに特別な状況があります。 定義スコープから XAML リソース参照を作成する UserControl は、独自の定義スコープ検索シーケンス内でそのリソースの検索をサポートできる必要があります。つまり、アプリ リソースにアクセスすることはできません。 UserControl の使用スコープから、リソース参照は、(読み込まれたオブジェクト ツリー内のオブジェクトから作成されたその他のリソース参照と同様に) その使用状況ページ ルートに対する参照シーケンス内にあるものとして扱われ、アプリ リソースにアクセスできます。
ResourceDictionary と XamlReader.Load
ResourceDictionary は、XamlReader.Load メソッドのルートまたは XAML 入力の一部として使用できます。 このような参照がすべて読み込みのために送信された XAML に完全に自己完結している場合は、その XAML に XAML リソース参照を含めることもできます。 XamlReader.Load は、その他の ResourceDictionary オブジェクトを認識しないコンテキストで XAML を解析します。Application.Resources も認識しません。 また、XamlReader.Load に送信された XAML 内から {ThemeResource}
を使用しないでください。
コードからの ResourceDictionary の使用
ResourceDictionary のシナリオのほとんどは、XAML でのみ処理されます。 ResourceDictionary コンテナーと、その中のリソースは、UI 定義ファイル内の XAML ファイルまたは XAML ノードのセットとして宣言します。 次に、XAML リソース参照を使用して、XAML のその他の部分からそれらのリソースを要求します。 それでも、アプリの実行中に実行されるコードを使用して ResourceDictionary の内容を調整したり、少なくとも ResourceDictionary のコンテンツにクエリを実行してリソースが既に定義されているかどうかを確認したりするシナリオもあります。 これらのコード呼び出しは ResourceDictionary インスタンスで行われるので、まず、FrameworkElement.Resources または Application.Current.Resources
を取得することで、オブジェクト ツリー内のどこかにある即時の ResourceDictionary を取得する必要があります。
C# または Microsoft Visual Basic コードでは、インデクサー (Item) を使って所定の ResourceDictionary 内のリソースを参照できます。 ResourceDictionary は文字列キー付きディクショナリであるため、インデクサーは整数インデックスではなく文字列キーを使用します。 Visual C++ コンポーネント拡張機能 (C++/CX) コードでは、Lookup を使います。
コードを使用して ResourceDictionary を調べたり変更したりする場合、Lookup や Item などのAPI の動作は、即時リソースからアプリ リソースに走査されません。XAML ページが読み込まれるときにのみ発生する XAML パーサーのビヘイビアーです。 実行時に、キーのスコープは、その時点で使用している ResourceDictionary インスタンスに対して自己完結型になります。 ただし、そのスコープは MergedDictionaries に拡張されます。
また、ResourceDictionary に存在しないキーを要求した場合は、エラーが発生しない可能性があります。戻り値は単に null として指定できます。 ただし、返された null を値として使用しようとすると、エラーが発生する可能性があります。 このエラーは、ResourceDictionary 呼び出しではなく、プロパティのセッターから発生します。 エラーを回避する唯一の方法は、プロパティが有効な値として null を受け入れた場合です。 このビヘイビアーと XAML 解析時の XAML 検索ビヘイビアーの違いに注意してください。解析時に XAML から指定されたキーを解決できないと、プロパティが null を受け入れた可能性がある場合でも、XAML 解析エラーが発生します。
マージされたリソース ディクショナリは、実行時にマージされたディクショナリを参照するプライマリ リソース ディクショナリのインデックス スコープに含まれます。 つまり、プライマリ ディクショナリの Item または Lookup を使用して、マージされたディクショナリで実際に定義されたオブジェクトを検索できます。 この場合、検索ビヘイビアーは解析時の XAML 検索ビヘイビアーに似ています。マージされたディクショナリに、それぞれが同じキーを持つ複数のオブジェクトがある場合、最後に追加されたディクショナリのオブジェクトが返されます。
Add (C# または Visual Basic) または Insert (C++/CX) を呼び出すことで、既にある ResourceDictionary に項目を追加できます。 品目は、即時リソースまたはアプリ リソースに追加できます。 これらのいずれかの API 呼び出しにはキーが必要です。これは、ResourceDictionary 内の各項目にキーが必要であるという要件を満たします。 ただし、実行時に ResourceDictionary に追加する項目は、XAML リソース参照には関係ありません。 XAML リソース参照に必要な検索は、アプリの読み込み時に XAML が最初に解析されたとき (またはテーマの変更が検出された場合) に発生します。 実行時にコレクションに追加されたリソースは使用できませんでした。ResourceDictionary を変更しても、そのリソースの値を変更しても、既に取得されたリソースは無効になりません。
実行時に ResourceDictionary から品目を削除したり、一部またはすべての項目のコピーを作成したり、その他の操作を行うこともできます。 ResourceDictionary のメンバー リストは、使用可能な API を示します。 ResourceDictionary には基になるコレクション インターフェイスをサポートするプロジェクションされた API があるため、API オプションは、C# または Visual Basic と C++/CX のどちらを使っているかによって異なります。
ResourceDictionary とローカリゼーション
XAML ResourceDictionary には、最初はローカライズされる文字列が含まれている場合があります。 その場合は、ResourceDictionary ではなくプロジェクト リソースとしてこれらの文字列を格納します。 XAML から文字列を取り出し、代わりに所有する要素に x:Uid ディレクティブ値を指定します。 次に、リソース ファイルでリソースを定義します。 XUIDValue という形式でリソース名を指定します。PropertyName とローカライズする必要がある文字列のリソース値。
カスタム リソース検索
高度なシナリオでは、このトピックで説明する XAML リソース参照検索ビヘイビアーとは異なる動作を持つクラスを実装できます。 これを行うには、CustomXamlResourceLoader クラスを実装し、StaticResource または ThemeResource を使用するのではなく、リソース参照の CustomResource マークアップ拡張機能を使用してそのビヘイビアーにアクセスできます。 ほとんどのアプリには、これを必要とするシナリオはありません。 詳細については、「CustomXamlResourceLoader」を参照してください。
関連トピック
- ResourceDictionary
- XAML の概要
- StaticResource のマークアップ拡張機能
- ThemeResource マークアップ拡張
- XAML テーマ リソース
- コントロールのスタイル指定
- x:Key 属性
Windows developer