こんにちは、働くC#プログラマーのさんさめです。
WPFでxamlを扱うとき
たびたびでてくる「{Binding Hoge}」といった記述。
これは、マークアップ拡張と呼ばれるものです。
こう書くとBindingできるって言われたから書いてるけど…
これって結局どういう意味なの?
この記事は、そんな方に向けて、
マークアップ拡張の読み方を、
Bindingを題材に解説します。
なぜBindingを題材に扱うかというと、
マークアップ拡張が入れ子構造になりやすいため、
仕様を知らないと非常に読みづらいからです。
(少なくとも昔のさんさめは、
割とおまじないチックに見様見真似で書いていました)
↓こういうのとか…
<Button Command="{Binding DataContext.RemoveCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}}"
Content="この行を削除"/>
この記事を読み終えるころには、
(少なくともBindingの)
マークアップ拡張が読めるようになり、
知らないマークアップ拡張に遭遇した時も、
意味を類推できますし、
適切に調べることができるようになります。
マークアップ拡張を読むときに抑えたい基本
マークアップ拡張とは、
非常にざっくり言ってしまうと
クラスインスタンスの生成をするためのものです。
つまり、
<TextBlock Text="{Binding Hoge}"/>
と書いたならば、
xamlが読み込まれた瞬間に
裏ではBindingクラスのインスタンスが生成されています。
これはつまり、
var binding = new Binding("Hoge");
と書いているのとほぼ同義です。
また、
<TextBlock Text="{Binding Hoge, Mode=OneWay}"/>
ならば、
var binding = new Binding("Hoge")
{
Mode = BindingMode.OneWay,
};
です。
ちなみに、{Binding Hoge}のところは
以下のように書くこともできます。
<TextBlock Text="{Binding Path=Hoge, Mode=OneWay}"/>
この場合は以下のような記述と同じとみなせるでしょう。
(厳密にはPathはstringではないので、これはビルドエラーですが)
var binding = new Binding()
{
Path = "Hoge",
Mode = BindingMode.OneWay,
};
とにかく、プロパティに値を代入しているだけです。
そして、特定のプロパティだけは、
プロパティ名の指定を省略できると。
それだけのことなのですね。
あれ、思ったより簡単?
実は、そうなんです。
マークアップ拡張は以下のような
書式で行うインスタンス生成と考えると、
非常に明快に頭に入ってきます。
- 「{」の直後がクラス名
- 「プロパティ名=値」をカンマ区切りで書くと、
プロパティに値をセットできる - モノによってはプロパティ名を省略していきなり値を書ける。
省略可能なプロパティはクラスによって異なる- BindingならPath
- StaticResourceならResourceKey
読み方の基本がお分かりいただけたでしょうか。
マークアップ拡張が入れ子になっても考え方は同じ
冒頭で出したサンプルのように、
マークアップ拡張が入れ子になっていても基本の考え方は一緒です。
<Button Command="{Binding DataContext.RemoveCommand,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ListBox}}}"/>
1つ1つ分解してC#コードにしていくと、
次のようになります。
var binding = new Binding("DataContext.RemoveCommand")
{
RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor)
{
AncestorType = typeof(ListBox),
}
};
対応付けを分かりやすくしてみました。
(※本来マークアップ拡張の中で改行はできないので注意)
こうしてみると、
実はそんなに怖くないことが分かります。
「{」が重なる上に、
途中で改行が挟めない関係上
1文が横に伸びやすいことが、
とっつきにくさの原因なのではないでしょうか。
まとめ
まとめです。
- マークアップ拡張はとっつきにくい
- xamlにおけるインスタンスの
特殊な生成法と考えると分かりやすい - 入れ子になっても考え方は同じ
- 横に長いと読む気が失せるので、
改行を適宜挟むと読みやすくなる
(ただしビルドは通らなくなるので理解したら戻す必要あり)
最後までお読みいただきありがとうございました。
コメント