7.7 リソース
7.7.1 リソースの管理
リソースという言葉には様々な意味が含まれますが、WPF においてリソースとはプログラムの中で使われるデータ的な性質のオブジェクトです。通常は、テキストやイメージ、音声、アイコン、ブラシ、その他の様々な情報がリソースであると考えることができます。WPF では、このようなデータをフレームワークの中で効率的に管理することができる基盤を提供しています。
実際にはあらゆるオブジェクトがリソースになる事ができますが、通常はグラフィカルな要素に対してデータとして作用するオブジェクトをリソースと指します。リソースは、リソースを使用するアプリケーションと関連付けられるため、関連付けを管理する仕組みが必要になります。
WPF では、リソースを管理するための System.Windows.ResourceDictionary クラスが提供されています。
[LocalizabilityAttribute(LocalizationCategory.Ignore)] public class ResourceDictionary : IDictionary, ICollection, IEnumerable, INameScope, ISupportInitialize, IUriContext
ResourceDictionary クラス事態は複雑なクラスではありません。実装しているインターフェイスを見ても理解することができますが、このクラスはリソースを保存する単純な辞書クラスです。キーとなるオブジェクトと、リソースを内部で関連付けます。
このクラスのコンストラクタは、パラメータを受け取りません。
public ResourceDictionary ()
ResourceDictionary に、リソースとなるオブジェクトを追加するには Add() メソッドを使います。
public void Add (Object key, Object value)
key にはキーとなるオブジェクトを、value にはキーに関連付けられるオブジェクトを指定します。
追加したオブジェクトを取得するには、インデクサを使います。
public Object this [Object key] { get; set; }
key に、取得したいオブジェクトに関連付けられているキーを指定します。インデクサは、キーに関連付けられているオブジェクトを返します。
ResourceDictionary に追加されているオブジェクトの数を取得するには Count プロパティを使います。
public int Count { get; }
Count プロパティは、ResourceDictionary オブジェクトが保有しているオブジェクトの数を返します。
これらのメソッドやプロパティは、すべて辞書オブジェクトを表す IDictionary インターフェイスや ICollection インターフェイスで宣言されているものなので、辞書クラスを扱ったことがあれば容易に理解できます。
using System; using System.Windows; using System.Windows.Controls; class Test { [STAThread] public static void Main() { ResourceDictionary rd = new ResourceDictionary(); rd.Add("Test1", "Kitty on your lap"); rd.Add("Test2", "Dote up a cat"); TextBlock textBlock = new TextBlock(); textBlock.FontSize = 30; textBlock.Text = "Test1=" + rd["Test1"] + "\nTest2=" + rd["Test2"]; Window wnd = new Window(); wnd.Content = textBlock; Application app = new Application(); app.Run(wnd); } }
コード1は、ResourceDictionary オブジェクトを生成して、"Test1" という名前と "Test2" という名前のキーで、文字列をリソースとして追加しています。この文字列は、そのまま表示する TextBlock オブジェクトのテキストとして設定しています。
7.7.2 オブジェクトのリソース
プログラムで ResourceDictionary をインスタンス化する必要はほとんどありません。FramelwrokElement を継承する WPF の描画要素は Resources プロパティから自分自身の ResourceDictionary を提供しています。
public ResourceDictionary Resources { get; set; }
このプロパティは FramelwrokElement クラスのものなので、WPF コントロールは全てリソースを保有する仕組みを持っていることになります。様々な形でデータを管理することができるプログラミング言語のコードではリソースを積極的に利用する場面は少ないかもしれません。このリソースの仕組みは、XAML でデザインを行うときに能力を発揮します。XAML は、スタイルやテンプレートなどのリソースを変数として保存する仕組みを持たないためです。
using System; using System.Windows; using System.Windows.Media; class Test { [STAThread] public static void Main() { Window wnd = new Window(); wnd.Resources.Add("TextColor", Brushes.Red); wnd.Resources.Add("Size", 30.0); wnd.Content = "Kitty on your lap"; wnd.Foreground = (Brush)wnd.Resources["TextColor"]; wnd.FontSize = (double)wnd.Resources["Size"]; Application app = new Application(); app.Run(wnd); } }
コード2は表示する Window オブジェクトの Resources プロパティに、前景色とフォントサイズを表すリソースを保存しています。その後、これらのリソースを取得してウィンドウの Foreground プロパティと FontSize プロパティにそれぞれ設定しています。
FrameworkElement オブジェクトに設定されているリソースは、ただの辞書ではありません。FrameworkElement クラスでは、リソースを検索する FindResource() メソッドを提供しています。このメソッドを使うことで、自分自身にリソースが存在していなくても、その親の FrameworkElement オブジェクトのリソースを検索します。
public Object FindResource (Object resourceKey)
resourceKey には、検索するリソースに関連付けられているキーを指定します。このメソッドを使うことで、複数のオブジェクトに適用させたいリソースを親 FrameworkElement に設定するだけで共有することができます。
using System; using System.Windows; using System.Windows.Controls; class Test { [STAThread] public static void Main() { Button button = new Button(); TextBlock textBlock = new TextBlock(); StackPanel panel = new StackPanel(); panel.Resources.Add("Text", "Kitty on your lap"); panel.Children.Add(button); panel.Children.Add(textBlock); button.Content = (string)button.FindResource("Text"); textBlock.Text = (string)textBlock.FindResource("Text"); Window wnd = new Window(); wnd.Content = panel; Application app = new Application(); app.Run(wnd); } }
コード3は、button オブジェクトや textBlock オブジェクトが表示するテキストをリソースから取得しています。しかし、それぞれのオブジェクト自身の Resources プロパティにはリソースを設定していません。しかし、FindResource() メソッドからリソースを検索しているため、親である StackPanel のリソースも検索されています。このプログラムの場合は、StackPanel のリソースからテキストを取得しています。もし、StackPanel にも該当のリソースが存在しない場合は、さらにその親を検索します。