双方向データバインディング

ASP.NETにはコントロールとオブジェクトのプロパティの値を連結して、表示と更新を同時に行う機能がある。

こんな感じで定義すれば、Hogeプロパティの値がテキストボックスに表示されて、値を変更してポストバックすれば自動的にプロパティに値が設定されるようになっている。

<asp:TextBox runat="server" ID="TextBox1" Text='<%# Bind("Hoge") %>'></asp:TextBox>

便利そうに見えるけどこれにはいくつか問題がある。

  1. データ連結に対応したコンテナコントロールのテンプレート内でしか使えない。
    (GridViewとかFormViewとか)
  2. ネストしたプロパティには対応していない。(Hoge.Nameみたいな)

1については、まだなんとかなるが、2は結構致命的でこれを解消するためにデータ構造を変える必要がある。
Spring.NETにはこれを解決するための方法として「双方向データバインディング」というものが用意されている。

使い方

まず、双方向データバインディングを使用したいページをSpring.Web.UI.Pageクラスから派生させる。

public partial class HogePage : Spring.Web.UI.Page {
}

データを連結するオブジェクトをページクラスのプロパティとして実装する。

public Hoge Hoge {
  get {
    return (Hoge)ViewState["hoge"];
  }
  set {
    ViewState["hoge"] = value;
  }
}

テキストボックスを追加して、InitializeDataBindingsメソッドをオーバーライドする。
BindingManagerのAddBindingメソッドで、バインドするコントロールとオブジェクトを指定する。

protected override void InitializeDataBindings() {
  BindingManager.AddBinding("TextBox1.Text", "Hoge.Name");
}

こんな風に第一引数にコントロールとプロパティ名、第二引数にプロパティ(ネスト可)を指定することで、双方向データバインディングが実現できる。

このやり方にももちろん問題があって、バインドするコントロールが増えれば記述する量も増えるし、なによりオブジェクトやコントロールを文字列で指定するので、型の制約を受けることができない。
あと、Nullable型のプロパティがバインドできない(未実装なだけか?)。それでも、コントロールから値を読み取って、オブジェクトに手動で設定するよりは手数が減るので生産性を上げることができる。

なによりデータ連結コンテナにたよる必要がないので、自由度が増すだろう。