.NET TIPS

[ASP.NET]Container.DataItemの正体は?

デジタルアドバンテージ
2003/09/12

 Repeater、DataList、DataGridなどのWebサーバ・コントロールでは、テンプレートを用いてデータソースの各項目を順に表示することができる。通常テンプレートの記述は次のようになる。

  <ItemTemplate>
    <%# Container.DataItem %>
  </ItemTemplate>

 この記述では、データソースの項目ごとにこのテンプレートが適用され、データ連結式である<%# Container.DataItem %>の個所がその項目の値に置き換えられて表示される。ところで、テンプレートの記述ではお約束のフレーズとして登場する「Container.DataItem」であるが、ContainerオブジェクトはASP.NETページの実体であるPageオブジェクトのメンバでもないし、Pageクラスの親クラスであるControlクラスなどにも見あたらない。

 いったいDataItemプロパティを持つこのContainerオブジェクトは何者で、どこから現れたのだろうか?

Container.DataItemの使用例

 Containerオブジェクトの正体を探るために、簡単なサンプル・プログラムを用意した。次のプログラムはRepeaterコントロールを使用してデータ連結を行う。

<%@ Page Language="C#" Debug="true" %>

<html>
<head>
  <script runat="server">

    void Page_Load(Object s, EventArgs e) {

      string[] cmajor = {"C", "C#", "D", "D#", "E"};

      MyRepeater.DataSource = cmajor;
      MyRepeater.DataBind();
    }

  </script>
</head>

<body>
  <form runat="server">
    <asp:Repeater id="MyRepeater" runat="server">
      <ItemTemplate>
        <%# Container.DataItem %>
      </ItemTemplate>
    </asp:Repeater>
  </form>
</body>
</html>
Repeaterコントロールを使用してデータ連結を行うC#のサンプル・プログラム(repeater.aspx)

 このサンプル・プログラムの実行結果は次の画面のようになる。テンプレート部分が、配列内の5つの各文字列(C、C#、D、D#、E)に展開され、表示される。

サンプル・プログラムの実行結果

 それではまず、「TIPS:[ASP.NET]ページから生成されたソース・コードを見るには?」の手順に従って、このサンプル・プログラムから生成されたC#のソース・コードを見てみよう。

Containerを宣言するメソッド

 自動生成されたソース・コードをテキスト・エディタで表示して「Container」を検索すると、Containerオブジェクトが設定されている次のようなメソッドが見つかるはずだ。

public void __DataBind__control4(object sender, System.EventArgs e) {
  RepeaterItem Container;
  DataBoundLiteralControl target;
  target = ((DataBoundLiteralControl)(sender));
  Container = ((RepeaterItem)(target.BindingContainer));
  target.SetDataBoundString(0, System.Convert.ToString(Container.DataItem));
}

 上記のサンプル・プログラムの場合、「Container」は__DataBind__control4メソッドでRepeaterItem型のローカル変数として宣言されている(太字部分)。

 RepeaterItemクラス(System.Web.UI.WebControls名前空間)は、Repeaterコントロールの各項目を表すクラスである。生成されたコードにはないが、データ連結を行ったときにはRepeaterコントロールの子コントロールとしてRepeaterItemクラスのオブジェクトが作成される(ここでは便宜上RepeaterItemコントロールと呼ぶことにする)。このサンプル・プログラムの場合、データソースの配列には項目が5つあるため、データ連結後にはRepeaterItemコントロールが5つ作成されることになる。

 続くメソッドの内容を見る前に、まずこの__DataBind__control4メソッドがいつ呼び出されるものかを確認しよう。

 ソース・コード内を「__DataBind__control4」で再度検索すると、次のようなメソッドが見つかるはずだ。

private Control __BuildControl__control4() {
  DataBoundLiteralControl __ctrl;
  __ctrl = new DataBoundLiteralControl(2, 1);
  this.__control4 = __ctrl;
  __ctrl.SetStaticString(0, "\r\n\t\t\t\t");
  __ctrl.SetStaticString(1, "\r\n\t\t\t");
  __ctrl.DataBinding += new System.EventHandler(this.__DataBind__control4);
  return __ctrl;
}

 変数「__ctrl」が参照しているコントロールのDataBindingイベントに、__DataBind__control4メソッドをイベント・ハンドラとして登録している(太字部分)。

 ここで変数「__ctrl」はDataBoundLiteralControlオブジェクトであり、実はこれはデータ連結式である“<%# 〜 %>”の実体である。DataBoundLiteralControlクラス(System.Web.UI名前空間)はデータ連結の結果、データソースの該当する項目をテキストで表示する際の表示個所となる(ここでは便宜上DataBoundLiteralコントロールと呼ぶ)。

 このDataBoundLiteralコントロールは、上記のRepeaterItemコントロールの子コントロールとなる。「TIPS:[ASP.NET]ページのトレース情報を出力するには?」に従ってトレース情報を表示させれば、これらのコントロールのツリーの様子を次のような画面で確認することができる。

サンプル・プログラム(repeater.aspx)で作成されるコントロールのツリー
DataBoundLiteralControl型のコントロールを子に持つRepeaterItem型のコントロールが5つ作成されているのが分かる。

 さて、DataBindingイベントはデータ連結が行われるときに発生する。このイベントが発生する元となるのは、もちろんMyRepeater.DataBindメソッドの呼び出しである。

 詳細部分はかなり省略して解説してきたが、ここまでをまとめると次のようになる。まずMyRepeater.DataBindメソッドを呼び出したときに、データソースの項目分のRepeaterItemコントロールとDataBoundLiteralコントロールが作成される。そして、各DataBoundLiteralコントロールについて、変数Containerを使用している__DataBind__control4メソッドが呼び出されるということだ。

変数Containerにセットされるオブジェクト

 呼び出されるタイミングが分かったところで、再度問題のメソッドを見てみよう。

public void __DataBind__control4(object sender, System.EventArgs e) {
  RepeaterItem Container;
  DataBoundLiteralControl target;
  target = ((DataBoundLiteralControl)(sender));
  Container = ((RepeaterItem)(target.BindingContainer));
  target.SetDataBoundString(0, System.Convert.ToString(Container.DataItem));
}

 このメソッドはDataBoundLiteralコントロールのイベント・ハンドラであるため、メソッドの第1パラメータであるsenderオブジェクトはDataBoundLiteralコントロールとなる。これを3行目で変数targetに代入した後、

Container = ((RepeaterItem)(target.BindingContainer));

により、問題となっているContainerオブジェクトにBindingContainerプロパティの値を代入している。BindingContainerプロパティについてはリファレンス・マニュアルに説明が記述されていないが、そのコントロールの親コントロールと考えて問題ないようである。つまり「Container」はデータ連結を行おうとしているRepeaterItemコントロールを参照しているローカル変数ということになる。

 データ連結式“<%# 〜 %>”を記述した場合には、aspxファイルがC#などのソース・コードに変換される際に、ローカル変数Containerを使用したメソッド(DataBindingイベントのイベント・ハンドラ)が必ず生成されるという前提があるため、データ連結式内でContainerオブジェクトが使用できるというわけだ。

 もちろん、Repeaterコントロールを使用している場合にのみ変数ContainerはRepeaterItem型となる。DataListコントロールの場合には、これはDataListItem型となるし、DataGridコントロールの場合にはDataGridItem型となる。これら3つの型(クラス)はいずれもDataItemプロパティを持っており、データ連結時にはあらかじめデータソースの項目の値がセットされる。

 ちなみに変数targetも必ず使用されるようなので、<%# Container.DataItem %>は、

<%# ((RepeaterItem)(target.BindingContainer)).DataItem %>

や、今回のサンプル・プログラムでは、

<%# ((RepeaterItem)(target.Parent)).DataItem %>

と記述してもプログラムは正しく動作する。

データ連結式の正体

 __DataBind__control4メソッドの残る最後の1行も見ておこう。

target.SetDataBoundString(0, System.Convert.ToString(Container.DataItem));

 targetはDataBoundLiteralControlクラスのオブジェクトである。このクラスのSetDataBoundStringメソッドもリファレンス・マニュアルには説明がないが、DataBoundLiteralコントロールに文字列をセットするためのものであると考えてよさそうだ。SetDataBoundStringメソッドの第2パラメータは、データ連結式内で記述した式をConvertクラス(System名前空間)のToStringメソッドにより文字列化したものとなる。

 この行に関しては、データ連結内の式がToStringメソッドのパラメータ部分に埋め込まれるだけのようである。このため、もし次のようなデータ連結式を記述した場合には、

<%# "ここにデータ連結式" %>

生成されるコードは次のようになる。

target.SetDataBoundString(0, System.Convert.ToString("ここにデータ連結式"));

 あるいは、次のようなデータ連結式を記述した場合には、

<%# DataBinder.Eval(Container.DataItem, "Length") %>

生成されるコードは次のようになる。

target.SetDataBoundString(0, System.Convert.ToString(DataBinder.Eval(Container.DataItem, "Length")));

 Containerオブジェクトとデータ連結式の正体をよく理解しておけば、複雑なテンプレートを記述する場合や、Container.DataItemに対してキャストが必要な場合にも難なく対応できるようになるはずだ。End of Article

カテゴリ:Webフォーム 処理対象:コントロール
使用ライブラリ:Repeaterコントロール(System.Web.UI.WebControls名前空間)
使用ライブラリ:RepeaterItemクラス(System.Web.UI.WebControls名前空間)
使用ライブラリ:DataBoundLiteralControlクラス(System.Web.UI名前空間)
使用ライブラリ:Convertクラス(System名前空間)
関連TIPS:[ASP.NET]ページから生成されたソース・コードを見るには?
関連TIPS:[ASP.NET]ページのトレース情報を出力するには?
 
この記事と関連性の高い別の.NET TIPS
[ASP.NET]DataGridコントロールでテンプレート列のセルの値を取得するには?
[ASP.NET]DataBinder.Evalメソッドを使用するメリット/デメリットは?
[ASP.NET]DataGridコントロールの行に通し番号を付けるには?
[ASP.NET]DataGridコントロールのハイパーリンク列で複数のパラメータをデータ連結するには?
[ASP.NET]DataGridコントロールの編集用テキストボックスを大きくするには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間