WPF/Silverlightの外観を簡単に変更できるコントロール・テンプレートとは? さらにUIフレームワークのUI要素の階層をまとめる。連載最終回。
powered by Insider.NET
前回に引き続きWPF UIフレームワークの“見た目”に関する機能を説明する。連載最終回となる今回は、コントロール・テンプレートを紹介したいと思う。
これまでのWindowsフォームでもそうであったように、WPF UIフレームワークのコントロールの“見た目”は、プロパティ設定により変更できる。例えばButtonコントロールの場合であれば、背景色はBackgroundプロパティ、枠線の色はBorderBrushプロパティで変更可能だ。
しかしながらWindowsフォームの場合、このようにして変更できるのは、ある程度の“見た目”である。例えばButtonコントロールのボタンの形そのものを変更したい場合、プロパティ設定では変更できない。Windowsフォームなど、これまでのWin32ベースのコントロールでこのような要求に応える場合、コントロールを自前で描画する「オーナー描画」と呼ばれる方法が用意されていた。しかしながら、オーナー描画はグラフィックス・メソッドなどを使用して、すべての描画を独自に行わなければならないため、コントロールに対する深い知識と多量のコードが必要になり、そう簡単に行えるものではなかった。
WPF UIフレームワークの場合、このような直接的にプロパティが用意されていない“見た目”の変更も、実はプロパティ設定だけで比較的簡単に変更できるようになっている。そのプロパティの名は「Templateプロパティ」である。
●Templateプロパティと既定のコントロール・テンプレート
WPF UIフレームワークのすべてのコントロール(Controlクラス、およびその派生クラス)はTemplateプロパティを持っており、このプロパティ対して「コントロール・テンプレート」を設定することで、ビジュアル構造を再定義できる仕組みになっている。
例えば、下記のXAMLコードの2つ目のボタンのように、Templateプロパティにnull(VBではNothing)参照を設定すると、デフォルトのコントロール・テンプレートが上書きされてしまうため、そのボタンの外観は表示されなくなる(外観が存在しない状態となる)。
<StackPanel>
<Border BorderBrush="Blue" BorderThickness="1"
Height="100" Padding="10">
<Button Content="Button"/>
</Border>
<Border BorderBrush="Blue" BorderThickness="1"
Height="100" Padding="10">
<Button Content="Button" Template="{x:Null}"/>
</Border>
</StackPanel>
このXAMLコードを実際に実行したのが、次の画面である。
このように、Templateプロパティにnull(VBではNothing)参照を設定すると、外観がまったくない状態になるという事実から、1つ目のボタンに見ることができるデフォルトの外観も、実際にはコントロール・テンプレートによって定義されているということが導き出せる。デフォルトの外観を定義するコントロール・テンプレートが、実行時にはボタンのTemplateプロパティに設定されているということだ。
そのため、設計時にTemplateプロパティの設定値を見ても、デフォルトのコントロール・テンプレートの内容を確認することはできない。デフォルトのコントロール・テンプレートの内容を確認する手段としては、以下のようないくつかの方法が存在する。
なお、WPFのコントロールの外観は、Windowsのデスクトップ・テーマによって異なる。このため、デフォルトの外観を定義しているコントロール・テンプレートは1つではなく、デスクトップ・テーマの数だけ存在する。
●固定的なコントロール・テンプレート
コントロール・テンプレートの概要を理解したところで、具体例を使って、より詳細な内容を見ていこう。下記のコードは、非常に単純な角が丸いボタンを、コントロール・テンプレートを使って作成した例だ。
<Button>
<!-- コントロール・テンプレートの定義 -->
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="LightGreen" CornerRadius="30" Padding="10">
<TextBlock Text="テンプレート"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
上記のXAMLコードによって表示されるButtonコントロールの外観は、以下の画面のようになる。
すでに説明したとおり、コントロール・テンプレートはTemplateプロパティの値として設定する。そのため、リソース、もしくはリソースとスタイルの両方を利用して、コントロール・テンプレートによる外観を複数のコントロールで共有できる。
以下のコードでは、先ほどのコントロール・テンプレートをリソースとして登録し、それを2つのButtonコントロールから参照している。
<StackPanel>
<StackPanel.Resources>
<ControlTemplate x:Key="ButtonTemplate" TargetType="Button">
<Border Background="LightGreen" CornerRadius="30" Padding="10">
<TextBlock Text="テンプレート"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
</ControlTemplate>
</StackPanel.Resources>
<Button Content="Button1"
Template="{StaticResource ButtonTemplate}" Margin="30"/>
<Button Content="Button2"
Template="{StaticResource ButtonTemplate}" Margin="30"/>
</StackPanel>
同じコントロール・テンプレートを参照しているため、以下の画面のように、2つのButtonコントロールは当然ながらどちらも同じ外観となる。
しかしながら、上記のコントロール・テンプレートには大きな問題がある。それは、それぞれのButtonコントロールにおいてContentプロパティを“Button1”、“Button2”と設定しているにもかかわらず、それがボタンの表示文字列に反映されていないという点だ。
この問題の原因は、コントロール・テンプレート内で固定的に“テンプレート”と表示するように定義してしまっている部分にある。
Copyright© Digital Advantage Corp. All Rights Reserved.