XAMLのBindingの基本についてのメモ

Windows ストアアプリの開発で使われるXAMLのBindingがいまいちわかってなかったのでメモ。

Bindingとは

XAMLで構成されるアプリケーションでは、Bindingという機構を使ってUIのコントロールのプロパティ (ターゲット) に任意のオブジェクトのプロパティ (ソース) の値をバインド (束縛) させることができます。Bindingによって紐付けられた二つのプロパティは、一方のプロパティ (ソース) の値を変更すると、他方のプロパティ (ターゲット) の値も自動的に同期されるようになります。

ターゲットとなるプロパティはDependency Property (依存プロパティ) である必要があります。Dependency Propertyは、値を記憶するためのメモリ領域や、値の変更の監視を行うための機能が実装されたプロパティです。SDKがデフォルトで提供しているコントロールを使用する場合は気にする必要はありませんが、カスタムコントロールを実装する際は自分でDependency Propertyを実装する必要があります。

ターゲットのプロパティをソースのプロパティにバインドするには、ターゲットのプロパティに{Binding Path=SourcePropertyName}というXAMLマークアップ拡張を埋め込みます。以下はTextBlockコントロールのTextプロパティにNameという名前のプロパティをバインドする例です。

<TextBlock x:Key="myTextBlock" Text="{Binding Path=Name}"/>

Path属性は省略することができます。つまり、前述のコードは以下のコードと等価です:

<TextBlock x:Key="myTextBlock" Text="{Binding Name}"/>

ソースの指定: DataContextプロパティ

ここで一つ疑問が生まれます。Nameプロパティはいったいどのオブジェクトから読み込まれるのでしょうか。答えはDataContextプロパティにあります。 以下にLayoutAwarePageクラスを継承したクラスのLoadStateメソッドのコードの一部を示します。

var person = new Person() { Name = "John Doe" };
myTextBlock.DataContext = person;

XAMLで定義したmyTextBlockという名前のTextBlockオブジェクトのDataContextプロパティに、Personオブジェクトを設定しています。Bindingで指定したプロパティは、DataContextプロパティで指定したオブジェクトから読み出されます。

DataContextプロパティが対象となる要素に設定されていない場合、ランタイムはさらに親の要素のDataContextプロパティの値を読みに行きます。以下のようにTextBlockの親要素としてGridがある場合を想定します。

<Grid x:Key="myGrid">
  <TextBlock Text="{Binding Name}"/>
</Grid>

TextBlockのDataContextプロパティが未設定の場合、ランタイムは親要素であるGridのDataContextプロパティを読みに行きます。以下のようにmyGridのDataContextプロパティにNameプロパティを持つ任意のオブジェクトを設定することで、子の要素 (ここではTextBlock) のプロパティの値を変更することができます。

myGrid.DataContext = person;

ソースの指定: Source属性

もう一つ別の例です。以上はDataContextプロパティを使ってバインドする例でしたが、DataContextプロパティを使わずにBindingマークアップ拡張のSource属性を指定することで静的にソースを指定することもできます。

<Page.Resources>
  ...
  <local:Person x:Key="myPerson" Name="John Doe"/>
</Page.Resources>

...

<TextBlock Text="{Binding Name, Source={StaticResource myPerson}}"/>

この場合、ランタイムはmyPersonResourceというオブジェクトのNameプロパティを読みに行きます。{StaticResource myPerson}はXAMLのリソース定義部で定義されたmyPersonというキーを持つPersonオブジェクトを参照するためのマークアップ拡張です。

まとめ

  • Bindingとは、二つのプロパティの値を同期させるための仕組み
  • Bindingマークアップ拡張機能によって、バインドするプロパティのソースとターゲットを指定できる
  • どのオブジェクトのプロパティを読み出すかは、DataContextプロパティかBindingマークアップ拡張のSource属性で指定する