WPF を習うとバインディングという言葉を耳にします。
バインディングは、2つのデータを同期させる機能を提供します。
バインディングしておけば、一方を変更するともう一方も変更されるということ、単純ですね。
何かの設定をしなければならないのは理解できます。
WPF では Source と Path を Binding クラスに渡すことでバインドを行います。
例を示します。
テスト用にテキストボックスとテキストブロックを用意
実行時の様子はこんな感じ↓
バインドしていないので、テキストボックスを変更してもテキストブロックは TextBlock のままです。
では、バインディングをしてみましょう。
コンストラクタで次のように記述します。
さっきと同じようにテキストボックスを変更すると…
IME の入力中の文字列まで持っていっていますね、これがバインディングの効果ですか。
はい、ということでバインディングができました。
ここまで C#コードからバインディングする方法を示しましたが XAML からでもバインディングは可能です。
同等のことを XAML でやってみましょう。
ハイライトした部分に注目。
Source を ElementName で、Path は Path で設定します。
コード側でバインドを用意しなくとも、XAML だけでバインディングはできるのです。
バインディングの基本的な学習はこんなところでしょうか?
(いえ、全然だめ、この先勉強したところ氷山の一角でした。)
バインディングを理解したら、WPF のテンプレートの機能も見てみましょう。
WPF の仕組みを習うと、表示ツリー ( VisualTree )という単語を耳にすると思います。
それは WPF 独特の概念で、コントロールを表示するための仕組みといったところでしょうか。
そんな「表示ツリー」を再定義、同じ事ですが、自分で好きなように定義し直す操作を「テンプレートを使用する」と言います。
ちょっと詳しくなった方は「テンプレート」を「新しい表示ツリーを作るためのファクトリ」という単語に置き換えて理解します。
まぁ、わからない方も、この先を読んで行けば理解できるのではないかと思います。
WPF のテンプレートには2種類あります。
ControlTemplate (コントロールの表示ツリーの作成)
DataTemplate (データの表示ツリーの作成)
です。
それぞれについて、見て行きましょう。
ボタンを例に、どんなものなのか見てみましょう。
テンプレートの定義は次のようにして行います。
ハイライトした部分に注目、クラスを定義して、ボタンの Template プロパティに設定するだけ。
あらかじめメインウィンドウに button1 を追加しています。
これに空のテンプレート(ターゲットは Button)を設定します。
見た目、何が難しいの?っていうレベル。簡単ですね。
実行結果は次の通り↓
赤くクレヨンで囲った位置に、ボタンがあるはずなのですが…見えませんね。
ちなみに VisualStudio のXAML デザイン画面では次のようになっています。
つまり、空のテンプレートを設定したところ、表示されなくなったというわけです。
まぁ、納得ですよね。Button の表示ツリーが無いのですから。(表示ツリーわかってない人、大丈夫ですか?)
では、このテンプレートにコントロールの表示ツリーを追加してみましょう。
次のように 青色の Rectangle を追加してみました。
ハイライトした部分に注目、要素ファクトリを表示ツリーに設定、その後に色や大きさを指定しています。
実行結果は次の通り。
ご理解いただけましたか? Button の下の階層に Rectangle という要素が追加されたのです。
テンプレートがその役割を果たし、新しいコントロールを Button の下に作成しています。
同じ事を XAML で実現してみます。
はい、これでコードでテンプレートを定義せずとも、同じ結果を得られます。
Button の Template に ControlTemplate を設定し、その中に Rectangle があると…
読めますね!コントロールテンプレートの基本です。
文字を表示したいなど、もともとの Button の機能のように、要素にコンテンツ表示機能をつけるには
次のように ContentPresenter を挟みます。
(Rectangle の下には ContentPresenter を置けないので Border に変更してます。)
実行結果は次の通り。
こんな感じで、ターゲットを TargetType="{x:Type ????}" で指定して、
その下の表示ツリーを任意のものにできるのが、コントロールテンプレートです。
データバインディングを簡単に見ていますが、テンプレートもバインディングできます。
ここまでテンプレート内部の要素の色や大きさ、スタイルに関するプロパティを設定してきました。
設定はテンプレートを定義するときにしか行えませんでした。
そんな事しなくても、テンプレートバインディングを行なっておけば、事足りるよと、そういう機能です。
結局コントロールテンプレートは定義します。
そのテンプレートを使用するコントロールについて
バインドされたプロパティを変更するだけで、テンプレートの指定のプロパティが変わるというのです。
どういうことなのか確認してみましょう。
ハイライトした部分に注目、プロパティを設定することでテンプレートのBorder の BorderBrush を変更できます。
実行結果は次の通り。
ならば、コードからプロパティを変更しても、それがテンプレートバインディングによって
テンプレートの外観データが変更される?
ハイライトした部分に注目。
ボタンの BorderBrush プロパティを変更しています。
この変更が反映され、実行結果は次のとおりになります。
コントロールテンプレートのテンプレートバインディング、理解できましたか?
あと、一度コントロールテンプレートを定義しておくと、それが見える子階層は Key を使って再利用できます。
次のコードを読めば、理解できる内容だと思います。
x:Key を使うには、一度 Resources に配置しないといけません。(Resources は誰でも持っています。)
今回は Windows.Resources の中に ControlTemplate を定義しました。
あとは、その下のハイライトした部分に示すように、Button の Template プロパティに静的リソースとして
x:Key を頼りに ControlTemplate を設定しています。で、テンプレートバインディングより
BorderBrush を変更することで、ボーダーの色を再設定できるのです。
実行結果は次のとおり。
初見のリソースとか、いろいろ組み合わさっているけど、大丈夫かな?
では、データテンプレートについて見て行きましょう。
データテンプレートはコントロールではなくデータ型を受け取って、表示ツリーを作成します。
次のコード例を見れば一発で理解できると思います。
なんでも良いので、データ型を定義します。
今回は int のプロパティを一つ持つテスト用クラスを用意しました。
表示テスト用に ContentControl を追加します。
デザインは次のとおり。(Button3 の下のやつが ContentContorol です。)
で、まずデータテンプレートを使わない場合どうなるか見てみましょう。
コンストラクタで ContentControl の Content に、データ型を渡してみます。
実行結果は次のとおり。
まぁ、当然ですよね。ContentControl からしてみれば、InnerData型?何こいつ、どう処理すれば良いの?
といった感じで、未知のデータ型について対処できません。
では、データテンプレートを使って、初期値 Count を TextBlock で表示するツリーを作成してみましょう。
次に示すコードは、データテンプレートの作成コードです。
ControlTemplate と形式が似ているので、覚えることは少ないです。
ターゲットを InnerData 型にして作成し、要素ファクトリに TextBlock を指定、そして
プロパティ Count をテキストとしてデータバインディングします。
作ったファクトリを表示ツリーに設定しています。
コードの理解については、大丈夫ですね。
あとは、作ったデータテンプレートを ContentControl に設定します。
すると…、データ型から表示ツリーを作ってくれるはずなので、Count をテキスト表示するはずです。
実行結果は次のとおり。
なるほどね、これがデータテンプレートです。
データ型から表示ツリーの作成に成功しました。
XAML で同じことを実現しようとすると、次のように記述する必要があります。
コードは Content へのデータ渡しの部分を残して、残りを削除しておきます。
理解する必要があるのはハイライトした部分だけです。
名前空間を切って、リソースに Key dataTemplate で、データテンプレートを定義し
ContentControl の ContentTemplate で設定しています。
実行結果は先ほどと同じです。いくらか読めるようになったのではないですかね?
追記:Data クラスが無いと怒られると思いますが、これ InnerData クラスをリネームしたものです。
Xaml に対し Count プロパティを持つ Data クラスが見えるようにしてあげる必要があります。
最後にリソースについて補足しておきます。
使い方は、これまで示してきたとおり、どんな要素も Resources プロパティを持っているので
ここにキーを指定して追加しておきます。
使うときはキーを指定するだけです。
また、使うときは StaticResource, DynamicResource を指定しますが
Static は以降変更しないものとして利用する場合に使用し、
Dynamic はバインドしているプロパティが変更されたときに更新したいときに使用します。
当然 Dynamic の方がパフォーマンスへの負荷が大きいので、必要な時のみ DynamicResource と指定します。
まぁ DataTemplate を使うときは DynamicResource が一般的なのかな?
はい、ということでここまで WPF のとっつきの部分を紹介してきました。
WPFって?どうやるの? みたいな疑問を持った時に最初に知っておきたいことをつらつら書いてみた感じです。
勉強しようと思って次に示す記事を、初っ端読んでみたところ全然ピンと来なかったんですよね。(自分のレベルが低いからかな…)
ただ、今なら多少は読める気がします。
あとは、パネルの配置、コントロールの配置、アニメーションなど、使いながら覚えていこうと思います。
長々と講座にお付き合いくださりありがとうございました。
とりあえず学んだことを活かして WPF でツールを作ってみるつもりなので
次回、その作ったツールをお見せできたらと思います。
2012/05/05 初記。