とりあえず半歩

学んだことを1日1個、簡単なことでも良いから記録していきたい。

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内の処理をハードコードしているけど、やっぱりひとつひとつ判定したほうがよいのだろうか。

参考