読者です 読者をやめる 読者になる 読者になる

the sea of fertility

C#er blog - http://ugaya40.net より移転。今度のブログは落ちない

XAML Tricks – C#じゃできなくてXAMLだからできる事 -

移管記事 Tips WPF XAML

この記事は2013/12/11に旧ブログ(http://ugaya40.net)に投稿した記事を私の旧ブログ閉鎖に伴い移管したものです。

XAML Advent Calendar 2013 11日目の記事です。

皆さんXAML使いこなしていますか?。XAMLって慣れていない間はどーしてもC#などの言語の考え方に縛られて活用しきれないものです。ですので今日は、C#では実現が難しく、XAML固有の機能を使うことでXAMLでの表現力を広げるTipsを2つほど解説します。

去年のWeakEventみたいなものを期待していた方、ライトなネタで申し訳ありません。

 

【その1】Attachableなコントロールを作る

f:id:m_onoue:20141225115249p:plain

こういうのどうしていますか?

ButtonのControlTemplateで実現しようとしても画像が異なるだけで複数のControlTemplateが必要になってしまいます。かといってわざわざUserControlも大げさでなんかしっくりきません。Buttonだけじゃなくて、いろんなコントロールに画像はさみたくなる事もまた多いです。

こういう時XAMLにはユーザーコントロールでもカスタムコントロールでもない(つまり継承系や新規コントロール作成ではない)、第3の選択肢があります。

そう、添付プロパティです。

 

例えば上の画像のXAMLはこうなっています。

f:id:m_onoue:20141225115316p:plain

 こうやって書ければ苦労しませんよね!。

以下のように画像をはさみたいコントロール(この場合はButton)のControlTemplateにAttachableImageを放り込めば上のように書けるわけです。(c:AttachableImage.ImageSource="hoge”を書かなければ普通のボタンのままですし、ControlTemplateにAttachableImageを入れていない場合にc:AttachableImage.ImageSource="hoge”を書いてても何も問題ありません、ただ何もおきないだけです。)

f:id:m_onoue:20141225115351p:plain

AttachableImageはImageコントロールを継承したもので、添付プロパティとしてImageSourceプロパティを持っています。ImageSourceプロパティが変化したら、自身のSourceプロパティ(Image.Source)にImageSourceと同じものをセットしているだけです。

AttachableImage自体も何も複雑な実装ではありません。添付プロパティを使う場合のごく定型的なコードです。

f:id:m_onoue:20141225115408p:plain

添付プロパティは確実にXAMLの表現力を広げるので、使わなきゃもったいないですよ!

【その2】:DataTemplate対応コントロールを作る

XAML最強の武器っていったら誰がなんと言おうとDataTemplateです。異論は認めません。そしてその最強の武器であるDataTemplateはC#では実現が不可能な機能を持つ唯一のXAML機能です。

DataTemlateをC#コードで組み立てようとするとFrameworkElementFactoryクラスを使うことになると思いますが、MSDNを見るとこういう注意書きがあります。

FrameworkTemplate のサブクラス (ControlTemplate や DataTemplate など) であるテンプレートをプログラムによって作成する場合、このクラスの使用はお勧めできません。このクラスを使用してテンプレートを作成した場合、一部のテンプレート機能が使用できなくなります。 テンプレートをプログラムによって作成する場合の推奨方法は、XamlReader クラスの Load メソッドを使用して文字列またはメモリ ストリームから XAML を読み込むことです。

FrameworkElementFactoryクラス – MSDNライブラリ

http://msdn.microsoft.com/ja-jp/library/system.windows.frameworkelementfactory(v=vs.100).aspx

後半に書いてあるXamlReader.Loadのお話しは「結局XAMLじゃないと書けないよ」と言っているだけですので、つまりDataTemplateの全機能を使用しようと思うとXAMLで定義を書かなきゃいけないんです。

さて、じゃあそのDataTemplateはどこで使うものでしょう。ItemsControlを使っているならもちろん使っているでしょう。WPFならDataTypeプロパティを使ってContentControlの中身を切り替えるのに使っている方もいるかもしれません。でももっとDataTemplateを使いたい。もっともっとDataTemplateを使いたい。僕はよくDataTemplate対応コントロールを作っています。別にそんな難しい話じゃないんです。

今回のサンプルは以下の通りです。

何の変哲もないTextBlockを継承したコントロールですが、なにやらDataTemplateがたくさん定義されています。

f:id:m_onoue:20141225115521p:plain

こいつにこんなViewModelをバインドしてやると・・・

f:id:m_onoue:20141225115532p:plain

こうなります!

image

さてこういうDataTemplate対応コントロールを作る際のポイントの解説です。

DataTemplateの中身

DataTemplateの中身は基本FrameworkElementしか入りません。しかし今回はInline要素を入れています。

そのためにこんなダミーのクラスをかましてあります。

f:id:m_onoue:20141225115706p:plain

こいつはDataTemplate内に存在しますが画面に現れることはありません。ただ直接はDataTemplate直下に定義できないInline要素を格納するためのコンテナとして用意してあります。DataTemplate対応コントロールを作る場合にはよく使うテクニックなので覚えておきましょう。

DataTemplateの中身のインスタンス

これは超簡単です。DataTemplateのLoadContentメソッドを呼ぶだけです。

作成してあげたらDataContextの設定を忘れずに!バインドできなくなっちゃいますよ!

f:id:m_onoue:20141225115649p:plain

本当は変更通知に対応したりとかいろいろ作りこめるんですが、まぁ今回はサンプルなのでシンプルにこの辺で。DataTemplate対応コントロールの作成、最初は敷居が高そうだなと感じるものですが意外と簡単なのでチャレンジあるのみです!

今回のサンプルソース

https://skydrive.live.com/redir?resid=BD1058705EC264F%211187

 

というわけで以上です。良いXAMLライフを!