第4回 WPFの「リソース、スタイル、テンプレート」を習得しよう:連載:WPF入門(2/3 ページ)
WPFはコントロールの外観を自由自在にカスタマイズできる柔軟性を備えている。これを実現する仕組みであるリソース、スタイル、テンプレートを解説する。
■スタイル
WPFは、HTMLでいうところのCSSのようなスタイル設定の機構を持っている。CSS同様、WPFでもスタイルを用いることで、UI要素の外観をカスタマイズ可能である。
●スタイルの定義
WPFのスタイルは、List 9に示すように、<Setter>要素(=プロパティの値を設定するための要素)のリストとして定義する。
<Style>要素のTargetTypeプロパティにはスタイルを適用したい型の名前を指定する。また、<Setter>要素のPropertyプロパティおよびValueプロパティに、それぞれ対象とするプロパティ名と値を指定する。
<Style TargetType="Button">
<Setter Property="Background" Value="DarkSeaGreen" />
<Setter Property="Foreground" Value="LightPink" />
</Style>
これまでのXAMLエディタでは、<Setter>要素に対するIntelliSenseが効かず、プロパティ名を覚えていなければスタイル設定ができないという、もどかしい状態が続いていた。しかし、最新のSilverlight 4 Tools for Visual Studio 2010をインストールすることで、WPFのXAMLエディタも同時に更新され、Figure 4に示すように、<Style>要素に対するIntelliSenseが有効になる。(Visual Studio 2010から、WPFとSilverlightのXAMLエディタが共通化された。Silverlight Toolsの更新でWPFも同時に更新されるのはこのためである)。
●スタイルの適用
FrameworkElementクラス(System.Windows名前空間)にはStyleプロパティがあり、このStyleプロパティに値を設定することで、定義したスタイルを適用できる。
スタイルは、FrameworkElementクラスのStyleプロパティに対して直接記述することもできるが、通常は、本稿の前半で解説したリソースの中で定義して利用する。スタイルとリソースは非常に相性がよく、リソースの中でスタイルを定義することで、複数のUI要素にスタイルを一斉適用可能である。特に、リソース中にx:Key XML属性を指定しないスタイルを定義することで、TargetTypeプロパティで指定した型の要素すべてに自動的にスタイルが適用される。
この3種類のスタイル利用(自動適用、明示的なリソース指定、直接記述)の例をList 10に、また、その表示結果をFigure 5に示す。
<StackPanel>
<StackPanel.Resources>
<!-- x:Key なしのスタイルを定義することで、
TargetType で指定した型すべてにスタイルを適用する -->
<Style TargetType="Button">
<Setter Property="Background" Value="LightBlue" />
<Setter Property="Foreground" Value="Red" />
</Style>
<!-- x:Key の明示 -->
<Style x:Key="MyButtonStyle" TargetType="Button">
<Setter Property="Background" Value="DarkSeaGreen" />
<Setter Property="Foreground" Value="LightPink" />
</Style>
</StackPanel.Resources>
<!-- スタイルの自動適用 -->
<Button Content="ボタン1" />
<!-- x:Key を指定して明示的にスタイルを適用 -->
<Button Style="{StaticResource MyButtonStyle}"
Content="ボタン2" />
<!-- スタイルを直接記述 -->
<Button Content="ボタン3">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="Gray" />
</Style>
</Button.Style>
</Button>
</StackPanel>
●スタイルの継承
<Style>要素は、BasedOnプロパティを指定することで、ほかのスタイルを継承できる。この仕組みにより、スタイルを部分的に書き換えたり、<Setter>要素を追加したりといったことが可能だ。
List 11にスタイルの継承例を、また、Figure 6にその表示結果を示す。この例では、背景色および前景色を指定するスタイルを継承し、さらにフォント・サイズを指定するスタイルを定義している。
<StackPanel Width="90">
<StackPanel.Resources>
<Style TargetType="Button">
<Setter Property="Background" Value="LightBlue" />
<Setter Property="Foreground" Value="Red" />
</Style>
<!-- 自動適用版のスタイルを基にして、新たにスタイルを作成 -->
<Style x:Key="MyButtonStyle" TargetType="Button"
BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="FontSize" Value="20" />
</Style>
</StackPanel.Resources>
<Button Content="ボタン1" />
<Button Style="{StaticResource MyButtonStyle}"
Content="ボタン2" />
</StackPanel>
●トリガー
スタイルの作成では、特定の条件下でのみ働くスタイルを定義したいという場面がしばしば出てくる。例えば、「マウス・カーソルが上に乗っているときや、クリックされたときだけスタイルを変えたい」というような要求は必ずといっていいほど出るだろう。このような要求に応えるため、WPFのスタイルではトリガーという仕組みを持っている。
具体的には、<Style>要素のTriggersプロパティを設定することで、特定の条件下でのみ働くスタイルを定義することができる。例えば、List 12のようなXAMLコードにより、マウス・カーソルが上に乗ったときだけ水色に、フォーカスを得ているときだけピンク色に変化するテキストボックスが得られる。
<StackPanel Width="60">
<StackPanel.Resources>
<Style TargetType="TextBox">
<Setter Property="Background" Value="LightGray" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="LightBlue" />
</Trigger>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Background" Value="LightPink" />
</Trigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
<TextBox Text="テキスト" />
</StackPanel>
<Style.Triggers>要素中に記述できるのは、Triggerクラスだけではなく、以下のようなものがある(いずれもSystem.Windows名前空間中のクラス)。
- Trigger: 特定のプロパティの値の変化をトリガーとして、Setterを用いてプロパティ値を変更する。
- MultiTrigger: Triggerを複数条件に対応させたもの。指定したすべての条件が満たされた場合にトリガーがかかる。
- DataTrigger: スタイル適用先のUI要素だけでなく、データ・バインディングされたデータを監視する。
- MultiDataTrigger: DataTriggerの複数条件版。
- EventTrigger: プロパティ値の変化ではなく、イベントの発生をトリガーとする。また、Setterではなくストーリーボードを使ったアニメーションによりプロパティ値を変化させる。
データ・バインディングやアニメーションに関しては次回以降で説明する。EventTriggerに関しても、アニメーションの回にあらためて説明を行う。
また、WPF 4では、状態の変化に応じたスタイルの変更を管理するために、新たにVisualStateManagerというクラスが追加された。このVisualStateManagerクラスは、もともとはSilverlightで実装されたものだが、.NET Framework 4でWPFにも輸入されることになった。
VisualStateManagerクラスの利用にはアニメーションの知識が必要なため、Triggerクラスを利用するより少し難易度は高い が*1、状態の管理が行いやすく、可能ならばこちらを用いた方がいいだろう。VisualStateManagerクラスに関しても、アニメーションの回で説明する予定である。
*1 Visual StudioのXAMLエディタにはアニメーション作成をサポートする機能がなく、複雑なアニメーションの作成が必要な場合にはExpression Blendの利用を考えてみるべきであろう。
Copyright© Digital Advantage Corp. All Rights Reserved.