This article has been localized into Japanese by the community.
リソース
WPFには非常に便利な概念が導入されています:それはコントロール・ローカル、ウィンドウ・ローカル、またはアプリケーション全体にグローバルにある、リソースとしてデータを格納するの能力です。データはWPFコントロールの階層の実際の情報から、ほとんど何にでもなり得ます。これは、ある場所においたデータが他のいくつかの場所から使えることを意味します。これは大変便利な機能です。
この概念はこのチュートリアルの後の方で議論する多くのスタイルとテンプレートで使われています。しかし、この章でも説明するように、この概念は他の多くのことにも使うことが出来ます。簡単な例で実演します。
<Window x:Class="WpfTutorialSamples.WPF_Application.ResourceSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="ResourceSample" Height="150" Width="350">
<Window.Resources>
<sys:String x:Key="strHelloWorld">Hello, world!</sys:String>
</Window.Resources>
<StackPanel Margin="10">
<TextBlock Text="{StaticResource strHelloWorld}" FontSize="56" />
<TextBlock>Just another "<TextBlock Text="{StaticResource strHelloWorld}" />" example, but with resources!</TextBlock>
</StackPanel>
</Window>
リソースにはx:key属性でキーが与えられ、このキーを使ってアプリケーションの他の場所からリソースを参照します。キーはStaticResourceマークアップ拡張と組みです。この例では単純な文字列をリソースに格納し、二つのTextBlockコントロールから使用しました。
スタティックリソースとダイナミックリソース
これまでの例ではリソースの参照するためにスタティックリソースを使いましたが、ダイナミックリソースという形式もあります。
一番の違いは、スタティックリソースはXAMLがロードされた段階で一度だけ評価される点です。もしそれ以降にリソースが変更されてもスタティックリソースを使っている場合は反映されません。
他方のダイナミックリソースは必要になったら評価されます。そしてリソースが変更されたときに再び評価されます。リソースが静的な値にバインドされた場合と、値が変更されたときいつでも知らせる機能を持った関数にバインドされた場合を考えて下さい。それがどのように動作するかはわかりませんが、何をいつ使うかがわかるはずです。ダイナミックリソースを使うと、設計時には存在もしないリソースを使うことが出来ます。アプリケーションのスタート時にコードビハインドからリソースを追加する場合などです。
その他のリソースの形式
単純文字列の共有は簡単でしたが、もっと他のことも出来ます。次の例では背景を塗るためのグラデーションブラシを伴った文字列の配列を格納します。これはリソースを使ってどれだけの事が出来るかを示してくれます。
<Window x:Class="WpfTutorialSamples.WPF_Application.ExtendedResourceSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="ExtendedResourceSample" Height="160" Width="300"
Background="{DynamicResource WindowBackgroundBrush}">
<Window.Resources>
<sys:String x:Key="ComboBoxTitle">Items:</sys:String>
<x:Array x:Key="ComboBoxItems" Type="sys:String">
<sys:String>Item #1</sys:String>
<sys:String>Item #2</sys:String>
<sys:String>Item #3</sys:String>
</x:Array>
<LinearGradientBrush x:Key="WindowBackgroundBrush">
<GradientStop Offset="0" Color="Silver"/>
<GradientStop Offset="1" Color="Gray"/>
</LinearGradientBrush>
</Window.Resources>
<StackPanel Margin="10">
<Label Content="{StaticResource ComboBoxTitle}" />
<ComboBox ItemsSource="{StaticResource ComboBoxItems}" />
</StackPanel>
</Window>
この例ではいくつかのリソースを加えました。その結果、ウィンドウには単純文字列、文字列の配列とLinearGradientBrushがあります。文字列はラベルとして、文字列配列はコンボボックスコントロールのアイテムとして、グラデーションブラシはウィンドウ内部の背景としてそれぞれ使われます。このようにほとんど全てのものがリソースとして格納できます。
ローカルリソースとアプリケーション全体のリソース
今の所、ウィンドウ全体からアクセスできるウインドウレベルのリソースを扱っています。
もし特定のコントロールのためのリソースが必要な場合は、ウィンドウの代わりに特定のコントロールにリソースを加えることで、ローカルなリソースを作ることが出来ます。これは、リソースを配置したコントロールの内部からしかアクセスできないという点を除いて、全く同じように機能します。
<StackPanel Margin="10">
<StackPanel.Resources>
<sys:String x:Key="ComboBoxTitle">Items:</sys:String>
</StackPanel.Resources>
<Label Content="{StaticResource ComboBoxTitle}" />
</StackPanel>
ここでは、StackPanelにリソースを加えて、子コントロールのLabelで使っています。StackPanel内部の他のコントロールも同様に使うことが出来ます。また子コントロールの子コントロールも同様にアクセスできます。しかしStackPanelの外側のコントロールはそのリソースにアクセスできません。
もし複数のウィンドウからアクセスする必要があっても同様に可能です。App.xamlファイルにはウィンドウやWPFのあらゆるコントロールのリソースを書くことが出来、App.xamlにリソースを書けばプロジェクトの全てのウィンドウとコントロールからグローバルにアクセスできます。これはウィンドウにリソースを書いた時と全く同じように機能します。
<Application x:Class="WpfTutorialSamples.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
StartupUri="WPF application/ExtendedResourceSample.xaml">
<Application.Resources>
<sys:String x:Key="ComboBoxTitle">Items:</sys:String>
</Application.Resources>
</Application>
使い方も同じです。WPFはリソースを見つけるためにローカルからウィンドウ、そしてApp.xamlへと自動的にスコープを広げていきます。
<Label Content="{StaticResource ComboBoxTitle}" />
コードビハインドからのリソース参照
今までは全てXAMLマークアップ拡張から直接リソースをアクセスしました。しかし、もちろんコードビハインドからも同様にアクセスできます。これはいくつかの状況で役立ちます。以前の例では異なる場所にどのようにリソースを格納するか見ました。ここでスコープの異なる3つのリソースをコードビハインドからアクセスします。
App.xaml:
<Application x:Class="WpfTutorialSamples.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
StartupUri="WPF application/ResourcesFromCodeBehindSample.xaml">
<Application.Resources>
<sys:String x:Key="strApp">Hello, Application world!</sys:String>
</Application.Resources>
</Application>
Window:
<Window x:Class="WpfTutorialSamples.WPF_Application.ResourcesFromCodeBehindSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="ResourcesFromCodeBehindSample" Height="175" Width="250">
<Window.Resources>
<sys:String x:Key="strWindow">Hello, Window world!</sys:String>
</Window.Resources>
<DockPanel Margin="10" Name="pnlMain">
<DockPanel.Resources>
<sys:String x:Key="strPanel">Hello, Panel world!</sys:String>
</DockPanel.Resources>
<WrapPanel DockPanel.Dock="Top" HorizontalAlignment="Center" Margin="10">
<Button Name="btnClickMe" Click="btnClickMe_Click">Click me!</Button>
</WrapPanel>
<ListBox Name="lbResult" />
</DockPanel>
</Window>
Code-behind:
using System;
using System.Windows;
namespace WpfTutorialSamples.WPF_Application
{
public partial class ResourcesFromCodeBehindSample : Window
{
public ResourcesFromCodeBehindSample()
{
InitializeComponent();
}
private void btnClickMe_Click(object sender, RoutedEventArgs e)
{
lbResult.Items.Add(pnlMain.FindResource("strPanel").ToString());
lbResult.Items.Add(this.FindResource("strWindow").ToString());
lbResult.Items.Add(Application.Current.FindResource("strApp").ToString());
}
}
}
3つの異なる"Hello, world!"メッセージを格納しました:一つはApp.xamlに、一つはウィンドウ内部に、もう一つはメインパネルローカルに。インターフェースはボタンとリストボックスから成ります。
コードビハインドではスクリーンショットのようにListBoxに各文字列を追加するボタンのイベントをハンドルしています。(もし有れば)リソースをオブジェクトとして返すFindResource()メソッドを使い、それをToString()メソッドで文字列に変換します。
それぞれのスコープでのFindResource()メソッドの使い方に注意して下さい。最初にパネル、次にウィンドウ、そして現在のApplicationオブジェクトです。既知のリソースを探すのは理解しやすいですが、既に述べたようにもしリソースが見つからなければ検索は階層を上がっていき、原則として3つの場合全てでパネルのFindResource()メソッドが使えます。すなわち、見つからなければウィンドウレベルまで、それでも見つからなければアプリケーションレベルまで。
同じことは逆の場合には当てはまりません。検索は木を下に下って行かないため、リソースがローカルのコントロールやウィンドウに定義されている場合はアプリケーションレベルから探し始めることは出来ません。