Visual Studio 2010 自習書 ~ Do-It-Yourself シリーズ ~
Visual Studio 2010 による Windows アプリケーション開発の基礎
第 6 回 リソース
更新日: 2010 年 12 月 13 日
ダウンロード (XPS、992 KB | PDF、969 KB)
目次
- リソースと XAML
- XAML (eXtensible Application Markup Language)
- リソースの定義
- アプリケーションの定義とリソース
- まとめ
WPF アプリケーションを活用する上で欠かせないリソースについて学びます。
ここでは、次のことを学習します。
- XAML の基礎
- リソースの使用
- ダイナミック リソース
- アプリケーション全体で使うリソース
1. リソースと XAML
リソースとは、アプリケーションで使うデータを、アプリケーション自身の中に埋め込んでおくものですが、ここではとくにユーザー インターフェイスのためのデータを、XAML に記述しておくものを指します。
リソースを使うためには、XAML に関する知識が不可欠です。これまでにも、XAML を使った例を紹介してきましたが、次回以降のスタイルやテンプレートでは、XAML を直接記述しなければなりません。
今回は、まず XAML の基礎について説明します。
ページのトップへ
2. XAML (eXtensible Application Markup Language)
WPF デザイナーと XAML エディターが連動していることからもわかるとおり、WPF デザイナーで作成するユーザー インターフェイスの内容は、XAML エディターで編集される XAML の定義と連動しています。
WPF エディターで、ウィンドウにコントロールを配置したり、プロパティ ウィンドウでプロパティを設定したり、イベント ハンドラーを割り当てると、それに対応して XAML の記述が追加・変更されます。
XAML は、もともとXML (eXtensible Markup Language) という記述言語を元に拡張されたものです。XML では「<タグ名>~</タグ名>」で表される要素の定義を組み合わせることで、データを表現します。タグにはしばしば「属性」を指定します。
要素は階層的に表現することができ、たとえば、ウィンドウの上にレイアウト パネルを配置し、レイアウト パネルの上にコントロールを配置するといった場合は、ウィンドウの開始タグ (<タグ名>) と終了タグ (</タグ名>) の間にレイアウト パネルの要素を定義し、レイアウト パネルを定義する開始タグと終了タグの間にコントロールを定義する開始タグから終了タグを記述します。
典型的な XAML の定義を次に示します。
<Window x:Class="WpfApplication6.MainWindow"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="240" Width="360">
<Grid>
<Button Margin="40">BIG BUTTON</Button>
</Grid>
</Window>
ウィンドウをあらわす Window タグには、コード ビハインドとして動作する C# プログラムのクラス定義 (x:Class) や XML の名前空間に関する定義 (xmlns、xmlns:x) が指定されています。さらに、ウィンドウ自身のタイトルや大きさも属性として指定されています。
ユーザー インターフェイスと XAML の関係を以下に示します。
ここで、ウィンドウ (Window) にはタイトル (Title) や大きさ (Height、Width) の属性が指定されており、ボタンには配置場所との間隔 (Margin) が属性として指定されています。
属性は、開始タグを記述する中 (<> の間) ではなく、次のように書くこともできます。
<Window x:Class="WpfApplication6.MainWindow"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml">
<Window.Title>MainWindow</Window.Title>
<Window.Height>240</Window.Height>
<Window.Width>360</Window.Width>
<Grid>
<Button>
<Button.Margin>40</Button.Margin>
BIG BUTTON
</Button>
</Grid>
</Window>
属性が文字列や数値の場合は、開始タグの中に記述する方が簡単です。複雑な場合は、上記のように記述しなければならないことがあります。今回学ぶリソースは、このような記述が必要です。
ページのトップへ
3. リソースの定義
最初に述べたとおり、リソースとはユーザー インターフェイスを定義するときに使うデータをあらかじめ XAML の記述の中に埋め込んでおくものです。リソースは、1) とくにプログラム中で何度も使われるデータに名前を付けて利用しやすくする、2) 後で修正するかもしれないデータをまとめて定義しておくといった目的があります。リソースは、ほとんどのコントロールに対して割り当てることができ、割り当てたコントロールや、その上に配置されているコントロールなどで使うことができます。
以下に簡単なリソースの使用例を示します。
<Window x:Class="WpfApplication6.MainWindow"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="240" Width="360">
<Window.Resources>
<SolidColorBrush x:Key="MyBrush">LightGreen</SolidColorBrush>
</Window.Resources>
<Grid>
<Button Margin="40" Background="{StaticResource MyBrush}">
BIG BUTTON
</Button>
</Grid>
</Window>
ここでは、ウィンドウ (Window) 要素にリソース (Resources) を割り当て、単一色のブラシを意味する SolidColorBrush のリソースを定義しています。リソースは、通常の要素と同じく開始タグ~終了タグで定義します。ただし、参照するための名前として「キー (x:Key) 」を指定する必要があります。ここでは、Button の Background プロパティでブラシ リソースを参照しています。StaticResource は「静的なリソース」として参照するという意味で、アプリケーションの実行中にリソースの値が変わらないことを前提としています。
このプログラムを実行した様子を示します。
ここで、MyBrush リソースの定義を次のように変更します。LinearGradientBrush は、グラデーション スタイルのブラシを定義するためのものです。
<Window.Resources>
<LinearGradientBrush x:Key="MyBrush">
<GradientStop Color="Red" Offset="0.0" />
<GradientStop Color="Orange" Offset="0.15" />
<GradientStop Color="Yellow" Offset="0.30" />
<GradientStop Color="LimeGreen" Offset="0.50" />
<GradientStop Color="Blue" Offset="0.70" />
<GradientStop Color="DarkBlue" Offset="0.85" />
<GradientStop Color="Magenta" Offset="1.0" />
</LinearGradientBrush>
</Window.Resources>
すると、このリソースを使用しているボタンは次のように表示されます。
リソースとして定義されたブラシは、そのリソースが定義されているコントロールの中にあるものであれば、どこでも利用できます。
前述の例で、<Grid>~</Grid> を次の内容に置き換えてみます。
<StackPanel>
<Button Height="50" Margin="10"
Background="{StaticResource MyBrush}">BUTTON</Button>
<Button Height="50" Margin="10"
BorderBrush="{StaticResource MyBrush}">BUTTON</Button>
<Ellipse Height="50" Margin="10"
Fill="{StaticResource MyBrush}" />
</StackPanel>
StackPanel に配置されているコントロールについて、それぞれボタンの背景 (Background プロパティ)、ボタンの輪郭 (BorderBrush プロパティ)、楕円の塗りつぶし (Fill プロパティ) として、MyBrush リソースが割り当てられています。
このプログラムを実行すると次のようになります。
MyBrush リソースは、ウィンドウ (Window) のリソースとして定義されているため、Window 内であればどこでも使えます。ただし、Window の開始タグは、リソース定義よりも前にあるため、開始タグの中で参照することはできません。
たとえば、ウィンドウの背景としてこのブラシを使いたい場合は、次のように記述できます。
...
</Window.Resources>
<Window.Background>
<StaticResource ResourceKey="MyBrush" />
</Window.Background>
<StackPanel>
...
このプログラムを実行すると次のように表示されます。
ダイナミック リソース
ここまで、リソースを参照する際には StaticResource を使っていました。これは、リソースの定義が静的 (変化しない) ことを前提にしていたためです。プログラム中でリソースの定義を変更する場合には、リソースを参照する際に DynamicResource を使います。
まず、前述の例で、以下のように StaticResource を DynamicResource に変更します。
...
<Window.Background>
<DynamicResource ResourceKey="MyBrush" />
</Window.Background>
<StackPanel>
<Button Height="50" Margin="10"
Background="{DynamicResource MyBrush}">BUTTON</Button>
<Button Height="50" Margin="10"
BorderBrush="{DynamicResource MyBrush}">BUTTON</Button>
<Ellipse Height="50" Margin="10"
Fill="{DynamicResource MyBrush}" />
</StackPanel>
</Window>
WPF デザイナーでボタンをダブルクリックするか、プロパティ ウィンドウを使って、いずれかの Button コントロールのイベント ハンドラーを次のように記述します。
private void Button_Click(object sender, RoutedEventArgs e)
{
this.Resources["MyBrush"] = new SolidColorBrush(Colors.Cyan);
}
ここでは、ウィンドウ自身に関連付けられている MyBrush リソースに、新たに作成する Cyan 色のブラシを代入しています。プログラムを実行してボタンを押すと、ブラシ部分が水色になることがわかります。
ページのトップへ
4. アプリケーションの定義とリソース
個々のウィンドウではなく、アプリケーション全体でリソースを共有したい場合もあります。この場合は、ソリューション エクスプローラーで App.xaml をダブルクリックして開きます (App.xaml は、ユーザー インターフェイスの定義ではないため、常に XAML エディターが開き、WPF デザイナーは使われません)。App.xaml の既定の状態を示します。
<Application x:Class="WpfApplication6.App"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
StartupUri は最初に起動するウィンドウを指定するプロパティです。XAML エディター中のカーソルを Application の定義に移動すると、プロパティ ウィンドウで ShutdownMode プロパティを変更したり、[イベント] タブで起動時 (Startup イベント) や終了時 (Exit イベント) に対するイベント ハンドラーを割り当てたりすることができます。
この App.xaml では、ウィンドウの場合と同じようにリソースを定義できます。ここで定義したリソースは、アプリケーションのすべてのウィンドウから参照できます。さきほどの MyBrush をアプリケーションのリソースとして定義する場合は、次のように記述します。このとき、ウィンドウのリソース定義 (Window.Resources) は削除しておきます。
<Application x:Class="WpfApplication6.App"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<LinearGradientBrush x:Key="MyBrush" >
<GradientStop Color="Red" Offset="0.0" />
<GradientStop Color="Orange" Offset="0.15" />
<GradientStop Color="Yellow" Offset="0.30" />
<GradientStop Color="LimeGreen" Offset="0.50" />
<GradientStop Color="Blue" Offset="0.70" />
<GradientStop Color="DarkBlue" Offset="0.85" />
<GradientStop Color="Magenta" Offset="1.0" />
</LinearGradientBrush>
</Application.Resources>
</Application>
リソース ディクショナリ
ある程度の規模のアプリケーションでは、アプリケーション全体に共通する膨大なリソースを必要とする場合があります。このときは、App.xaml にすべてのリソースを定義する代わりに、リソースを定義した外部ファイルを参照する方が便利です。このために、リソース ディクショナリという独立したファイルでリソースを定義し、これを App.xaml やウィンドウ用の .xaml から参照できます。
プロジェクトにリソース ディクショナリを追加するには、ソリューション エクスプローラーでプロジェクト名を右クリックし、[追加] - [新しい項目] で「リソース ディクショナリ」を選びます。
ここでは、MyDictionary.xaml という名前で追加します。App.xaml で定義したリソースを、次のように MyDictionary.xaml に移します。
<ResourceDictionary xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml">
<LinearGradientBrush x:Key="MyBrush" >
<GradientStop Color="Red" Offset="0.0" />
<GradientStop Color="Orange" Offset="0.15" />
<GradientStop Color="Yellow" Offset="0.30" />
<GradientStop Color="LimeGreen" Offset="0.50" />
<GradientStop Color="Blue" Offset="0.70" />
<GradientStop Color="DarkBlue" Offset="0.85" />
<GradientStop Color="Magenta" Offset="1.0" />
</LinearGradientBrush>
</ResourceDictionary>
App.xaml には、このファイルを読み込むように、リソース ディクショナリの記述を追加します。
<Application x:Class="WpfApplication6.App"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary Source="MyDictionary.xaml" />
</Application.Resources>
</Application>
これで、さきほどと同じようにアプリケーションが動作します。
リソース ディクショナリは、ウィンドウやコントロールのリソースで使うこともできます。ただし、1 つの Resources の中には、1 つの ResourceDictionary しか記述できません。複数のリソース ディクショナリを読み込むためには、次のように MergedDictionaries 属性で指定する必要があります。
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="MyDictionary.xaml" />
<ResourceDictionary Source="(リソース ディクショナリ名)" />
...
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
ページのトップへ
5. まとめ
今回は、ユーザー インターフェイスのためのデータを共有するリソースについて学びました。今回は、リソースの題材としてブラシを取り上げましたが、次回以降に説明するスタイルやテンプレートでもリソースは大いに活用できます。
次回はスタイルについて学びます。