WPFでコントロールの外見をカスタマイズする方法を解説します。
コントロールをカスタマイズというとControlTemplateとDataTemplateがありますが、この記事ではControlTemplateを解説します。
ControlTemplateとDataTemplateの違いについてはこちら:
あとで記載します。。。
ControlTemplateとは
ControlTemplateとは、WPFコントロールのデザインの定義です。独自のControlTemplateを定義、適用することでWPFコントロールの外見を変更することができます。
コントロールの構造(イメージ)
基本的にコントロールは複数のUI要素の組み合わせで作られており、ControlTemplateではその組み合わせや形を自由に再定義することができます。
(↑実際はもっと複雑かもですがイメージとして・・・)
コントロールデザイン変更の例
ControlTemplateを使用してボタンコントロールの形状を『星と円』を組み合わせた形に変更した例を示します。
カスタムボタンには『Grid』⇒『星』⇒『円』⇒『Content』の順で下からUI要素を重ねたControlTemplate定義を適用しています。
本来の四角形の領域でなく、見た目通り星と円の部分のみボタンが反応していることがわかります。ControlTemplateではこのように任意の形状のUI要素を組み合わせ、一つのコントロールとして見た目だけでなく反応領域まで自由に整形することができます。
(※クリック時にマウスカーソル周りに黄色い円を出していますが、これは録画ソフトの機能なのでWPFで制御しているものではありません)
ControlTemplateの記述
ControlTemplateはリソースとして定義し、対象のコントロールに適用します。
サンプルコード
以下に例で示したカスタムボタン(星+円)の定義コードを記述します。
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
<!-- リソース定義 -->
<StackPanel.Resources>
<!-- 1.星円ボタンのリソース -->
<ControlTemplate x:Key="StarButtonTemplate" TargetType="Button">
<!-- ①コントロールのデザイン定義 -->
<Grid>
<!-- 星型の配置 -->
<Polygon
x:Name="bd"
Fill="{TemplateBinding Background}"
Points="50 0 79 90 2 35 92 35 20 90"
Stroke="{TemplateBinding BorderBrush}" />
<!-- 円の配置 -->
<Ellipse
Width="60"
Height="60"
Fill="LightPink" />
<!-- Contentの配置 -->
<ContentPresenter
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
<!-- ②コントロール操作をトリガーとした見た目の変更 -->
<ControlTemplate.Triggers>
<!-- マウスオーバー時の背景色設定 -->
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="bd" Property="Fill" Value="Red" />
<Setter TargetName="bd" Property="Stroke" Value="Blue" />
</Trigger>
<!-- ボタンクリック時の背景色設定 -->
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="bd" Property="Fill" Value="Blue" />
<Setter TargetName="bd" Property="Stroke" Value="Red" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</StackPanel.Resources>
<!-- 2.画面上に実際にボタンを配置 -->
<!-- 星型ボタン -->
<Button
Width="100"
Height="100"
Margin="10"
Background="Yellow"
BorderBrush="Black"
BorderThickness="3"
Content="ABC"
Foreground="Black"
Template="{StaticResource StarButtonTemplate}" />
</StackPanel>
このソースコードは以下を記述しています。
- 1.カスタムボタンのControlTemplateをリソース定義
- ボタンのカスタムデザインを定義
- ボタンに対するトリガーアクションを定義
(マウスオーバー、クリック)
- 2.画面上にボタンを配置&ControlTemplateリソースを適用
詳細を次章で解説します。
コードの解説
1.①デザイン定義
<ControlTemplate>タグにコントロールの構造を記載します。
今回のカスタムボタンは『Grid』⇒『星』⇒『円』⇒『Content』の順で下から図形を重ねた構造にしています。
各図形(円、星)とContentを重ねるために一番下にGridを配置していますが、並べて配置したい場合はStackPanelを使用すると良いでしょう。(その辺は画面上にコントロールを配置するときと同様、自由に配置できます)
TemplateBinding
TemplateBindingによりボタンのプロパティに設定された値を継承できます。
今回の例では星の背景色をボタンのBackgroundプロパティ経由で外から指定しています。
継承先プロパティ = {TemplateBinding 継承元プロパティ}
ContentPresenter
設定されているデータ(Content)を表示するためのUI要素です。ControlTemplateではContentのUI要素も1要素として扱うため、明示的にContentPresenterの配置が必要です。(配置しないとContentが表示されなくなります。)
1.②トリガーアクション定義
ControlTemplate内でトリガーアクション(条件成立時にプロパティの値を設定する動作)を指定できます。<ControlTemplate>タグ内に<ControlTemplate.Triggers>タグで囲って定義します。
<ControlTemplate.Triggers>
<Trigger Property=トリガーとして監視するプロパティ Value=トリガー成立条件>
<Setter TriggerName=変更対象UI要素名 Property=変更対象プロパティ名 Value=設定値 />
<Setter TriggerName=変更対象UI要素名 Property=変更対象プロパティ名 Value=設定値 />
・・・
</Trigger>
</ControlTemplate.Triggers>
ControlTemplate適用先のコントロール(今回はボタン)が有するプロパティ名とトリガー成立条件をTriggerタグに設定します。トリガー成立時(プロパティの値=Valueとなった場合)、トリガーアクションとして配下のSetter処理が実行されます。
Setterによりプロパティ値を変更する際、変更対象となるUI要素名を指定していることに注意してください。デザイン定義部でx:Nameで定義した名前を指定しています。(今回は星を指定してプロパティを変更しています)
トリガーとして監視するプロパティとして、IsMouseOverやIsPressed、IsEnabledなどが代表的です。その他にも多々ありますので適用先コントロールのプロパティを確認してください。
2.ControlTemplateの適用
定義したControlTemplateを適用するにはボタンのTemplateプロパティに設定します。
<Button
Template="{StaticResource ControlTemplateのリソース定義名}" />
動的に反映する必要はないのでStaticResourceとして適用します
まとめ
ControlTemplateではContentも含めコントロール全体の構成をカスタマイズできます。アプリケーション開発では独自のコントロールデザインを求められることが多々あります。ControlTemplateをマスターしてお洒落なコントロールを作りましょう。
関連としてDataTemplateについても別途解説していますので、ぜひご参照ください。
勉強中の身ですので、誤りや不備等ありましたらご指摘いただけますと幸いです。