ITemplateでカスタムテンプレート作成
課題
GridViewのTemplateFieldに自前のテンプレートを用いる。
GridViewのFooterでデータ追加処理を実現するためにはTemplateFieldを用いることは以前調べた。GridViewの列を静的に用意するならばVisual Studioのデザイナを使ってしまえば簡単にTemplateFieldを作れる。しかし、今回はGridViewの列を動的に追加したい。そのために、ITemplateインタフェースを継承し、実装する。
実行
今回はTextBoxを1つ持つカスタムテンプレートを作る。
テンプレート内に表示するコントロールはITemplate.InstantiateInメソッド内で作成し、同メソッドの引数のコントロールに追加する。引数のコントロールが何かっていうと、テンプレートを適用してテンプレート内のコントロールを表示ためのコントロール。テンプレート内に表示するコントロールを子とするなら、それらの親となるコントロールのこと。例えば、今回の場合はGridViewの各セルを表すDataControlFieldCellコントロールが親コントロールで、その中に表示するTextBoxが子コントロール。
InstantiateInメソッド内で子コントロールを追加するとき、子コントロールのDataBindingイベントも一緒に追加しておくとGridViewへデータソースを追加した時に子コントロールへのデータバインドもできる。
以下はテストで書いたコード.
using System; using System.Data; using System.Web.UI; using System.Web.UI.WebControls; namespace GridViewTest { public class EditTemplate : ITemplate { public string Text { get; set; } private string ID; public EditTemplate(string id) { this.ID = id; } /// <summary> /// カスタムテンプレート内の子コントロールを定義、親コントロールに追加. /// </summary> /// <param name="container">親コントロール.</param> public void InstantiateIn(Control container) { TextBox tb = new TextBox(); tb.ID = this.ID; tb.DataBinding += new EventHandler(this.BindData); container.Controls.Add(tb); } /// <summary> /// 子コントロール(この場合はTextbox)のデータバインド時に実行されるメソッド. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> public void BindData(object sender, EventArgs e) { TextBox tb = (TextBox)sender; GridViewRow container = (GridViewRow)tb.NamingContainer; DataRowView drv = (DataRowView)container.DataItem; DataRow r = drv.Row; tb.Text = r[tb.ID].ToString(); } } }
TextBoxを1つもつカスタムテンプレートクラスのつもり。GridViewで使うことを想定している。
コンストラクタで子コントロールのIDを指定できるようにしてる。
InstantiateInメソッド内でTextBoxコントロールを定義、DataBindingイベントを追加、最後に親コントロールにTextBoxを追加してる。
DataBindingイベント時に実行されるメソッドBindDataでは、子コントロールのTextBoxを取得してバインドされたデータを表示するような処理をする。
上記のテストコードではバインドしているデータソースはDataTableで、DataColumnのColumnNameとTextBoxのIDを同じにすることでバインドしているデータを表示できるようにしている。
評価
DataBndingイベントにBindDataメソッドを追加したように、子コントロールにデータバインドしたときに表示できるようにしておくのが楽だった。今までGridViewのRowDataBoundイベントで頑張ってたのでコードがぐちゃぐちゃしてたのが見難くて嫌だった。それが前よりも見通し良くなったのでスッキリ。
BindData内の処理をハードコードしているけど、やっぱりひとつひとつ判定したほうがよいのだろうか。