かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

WPF4.5入門 その51 「リソース」

ここでは、リソースについて説明します。WPFのコントロールには、ResourceDictionary型のResourcesというプロパティが定義されています。ResourceDictionaryクラスの中には、画像・文字列・オブジェクトなど様々なものを名前をつけて保持することが出来ます。そして、保持しているリソースにはXAMLやプログラムから参照して使うことが出来ます。

リソースの定義

リソースの定義は、通常WindowやAppクラスのResourcesプロパティに定義します。以下にApp.xamlにブラシのリソースを2つ定義する例を示します。

<Application x:Class="ResourceSample01.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ImageBrush x:Key="AnthemBrush" ImageSource="anthem.jpg" />
        <SolidColorBrush x:Key="RedBrush" Color="Red" />
    </Application.Resources>
</Application>

リソースは、x:Key属性で名前をつけて定義します。このx:Keyで指定した値を元にXAMLやプログラム内からリソースにアクセスします。

App.xamlにリソースを定義すると、全てのWindowから共通で使用できるというメリットがあります。共通で使用するリソースはApp.xamlで定義をして、Window固有のリソースはWindowで定義して利用するのが一般的です。例外的な使い方として、各コントロールのResourcesプロパティにリソースを定義する方法もありますが、この場合、そのコントロール内でしか利用できないリソースとなります。

リソースの参照方法

リソースを参照する方法は、大きくわけて3つあります。StaticResourceマークアップ拡張を使う方法、DynamicResourceマークアップ拡張を使う方法、プログラムからアクセスする方法です。

StaticResourceマークアップ拡張は、実質的にはリソースの値を代入するのと等価です。DynamicResourceマークアップ拡張は、設定したキーのリソースが変更されるかどうかを実行時に監視していて、リソースが変わったタイミングで再代入が行われます。以下のように、BorderのBackgroundプロパティにAnthemBrushをStaticResourceマークアップ拡張とDynamicResourceマークアップ拡張で設定します。

<Border x:Name="border" Width="100" Height="100" Background="{StaticResource AnthemBrush}" />
<Border Width="100" Height="100" Background="{DynamicResource AnthemBrush}" />

この状態で、以下のようにAnthemBrushを置き換えるコードを記述します。

App.Current.Resources["AnthemBrush"] = new SolidColorBrush(Colors.Blue);

この状態で、プログラムを実行すると、以下のような結果になります。

f:id:okazuki:20140906124354p:plain

DynamicResourceマークアップ拡張を使用したほうが実行時に動的にリソースの変更に対応できていることが確認できます。DyanmicResourceマークアップ拡張を使うと、例えばアプリケーションのテーマの切り替えといったことが可能になります。しかし、必要でない限りStaticResourceマークアップ拡張を使うべきです。その理由は、単純にStaticResourceマークアップ拡張のほうがDynamicResourceマークアップ拡張よりもパフォーマンスが良いからです。

StaticResourceマークアップ拡張を使う時の注意点として、単純な代入という特徴から、使用するよりも前でリソースが定義されてないといけないという特徴があります。DynamicResourceマークアップ拡張は、このような制約が無いため、どうしても前方でリソースの宣言が出来ないときもDynamicResourceマークアップ拡張を使う理由になります。

マークアップ拡張を使う以外にコードからリソースを参照する方法を示します。

var brush = (SolidColorBrush)this.FindResource("RedBrush");
this.border.Background = brush;

FindResourceメソッドを使うことで、起点となるインスタンス(Windowなど)からAppクラスまで親へ親へリソースを探して最初にみつかったものを返します。見つからない場合は例外を返します。存在するかどうかがわからないリソースを参照する場合はTryFindResourceメソッドを使ってください。

過去記事