次の方法で共有


方法 : ASP.NET Web サーバー コントロールのテンプレートを動的に作成する

更新 : 2007 年 11 月

テンプレート コントロールを操作する場合、実行するまで、どのテンプレートが必要か、またはテンプレートにどのテキストまたはどのコントロールを含める必要があるか、わからない場合があります。このような場合、コードで動的にテンプレートを作成できます。

0e39s2ck.alert_note(ja-jp,VS.90).gifメモ :

テンプレートをユーザー コントロールとして作成し、作成したテンプレートをページ上のコントロールに動的にバインドすることもできます。詳細については、「方法 : template 宣言された ASP.NET ユーザー コントロールを作成する」を参照してください。

テンプレートを使用するすべてのコントロール (DataListRepeaterGridViewFormViewDetailsView など) に関して、テンプレートをコードで作成できます。GridView コントロールの場合は、他のコントロールで使用される行レイアウトのテンプレートではなく、列を定義するテンプレートを使用します。

0e39s2ck.alert_note(ja-jp,VS.90).gifメモ :

GridView コントロールのテンプレート列の作成には、他のテンプレート コントロールと比較して異なる点がいくつかあります。詳細については、「GridView Web サーバー コントロールにおけるカスタム列の作成」を参照してください。

テンプレート クラスの作成

動的なテンプレートを作成するには、テンプレート クラスを作成し、必要に応じてそのクラスをインスタンス化します。

テンプレート クラスを作成するには

  1. System.Web.UI.ITemplate インターフェイスを実装する新しいクラスを作成します。

  2. オプションで、どの種類のテンプレート (ItemTemplate、AlternatingItemTemplate など) を作成するかを決定するためにクラスが使用する値をクラスのコンストラクタに渡します。

    0e39s2ck.alert_note(ja-jp,VS.90).gifメモ :

    テンプレートの種類をコンストラクタに渡すときは、ListItemType 型でコンストラクタにパラメータを追加するのがタイプ セーフな方法です。ListItemType 列挙値は、RepeaterDataList などのリスト コントロールに対して使用できるテンプレートの種類を定義します。

  3. クラス内に、ITemplate インターフェイスのメンバである InstantiateIn メソッドを実装します。

    このメソッドは、テキストのインスタンスおよびコントロールを指定されたコンテナに挿入します。

  4. InstantiateIn メソッドで、テンプレート項目のコントロールを作成し、そのプロパティを設定した後でコントロールを親の Controls コレクションに追加します。

    親コントロールへは、InstantiateIn メソッドに渡される参照をとおしてアクセスできます。

    0e39s2ck.alert_note(ja-jp,VS.90).gifメモ :

    静的テキストを Controls コレクションに直接追加することはできません。コントロール (たとえば Literal コントロールや LiteralControl コントロール) を作成し、Text プロパティを設定してからコントロールを親コレクションに追加します。

  5. データ バインディングを必要とするコントロールの場合、コントロールの DataBinding イベントを処理するメソッドを作成し、バインドします。このイベントは、テンプレート項目が作成されてコントロールがすべて追加された後に発生し、データをフェッチしてコントロール内で使用できるようにします。

    0e39s2ck.alert_note(ja-jp,VS.90).gifメモ :

    デザイン時にテンプレートを定義する場合とは異なり、テンプレート内にコントロールを作成するときに、データ バインディング式を文字列として埋め込むことはできません。データ バインディング式は、テンプレートが作成される前にコードに変換されるためです。

    DataBinding イベントのハンドラでは、コントロールの内容を操作できます。通常は (必須ではありません)、データをフェッチしてそれをコントロールの Text プロパティ (または他のプロパティ) に割り当てます。

    0e39s2ck.alert_note(ja-jp,VS.90).gifメモ :

    ASP.NET Web ページのデータ バインディングの情報については、「ASP.NET でのデータ アクセス」を参照してください。

    データ連結を動的テンプレートに追加するには、次の操作を行う必要があります。

    • テンプレート内に作成したコントロールにデータ バインディング イベント ハンドラを追加します。

    • 連結するハンドラを作成します。このハンドラで、連結するデータを取得し、それを連結先のコントロールの適切なプロパティに割り当てます。

      0e39s2ck.alert_note(ja-jp,VS.90).gifメモ :

      テンプレートに複数の種類のコントロールがある場合は、コントロールの種類ごとに異なるデータ バインディング イベント ハンドラを作成する必要があります。

    ITemplate インターフェイスを実装する MyTemplate というテンプレート クラスを次の例に示します。MyTemplate クラスは、ListItemType 列挙値を受け取るコンストラクタを定義して、作成するテンプレートの種類を示します。テンプレートの種類によって、異なる種類のコントロールが作成され、PlaceHolder コントロールに追加されて、さらに親コントロールの Controls コレクションに追加されます。ItemAlternatingItemListItemType の場合、Item_DataBinding というイベント ハンドラが作成されます。

    描画される Web ページには、代替項目のテンプレートに異なる背景色を持つ HTML テーブルが作成されます。

    Public Class MyTemplate
        Implements System.Web.UI.ITemplate
    
        Dim templateType As ListItemType
    
        Sub New(ByVal type As ListItemType)
            templateType = type
        End Sub
    
        Public Sub InstantiateIn(ByVal container As System.Web.UI.Control) _
          Implements System.Web.UI.ITemplate.InstantiateIn
    
            Dim ph As New PlaceHolder()
            Dim item1 As New Label()
            Dim item2 As New Label()
            item1.ID = "item1"
            item2.ID = "item2"
    
            Select Case (templateType)
                Case ListItemType.Header
                    ph.Controls.Add(New LiteralControl("<table border=""1"">" & _
                        "<tr><td><b>Category ID</b></td>" & _
                        "<td><b>Category Name</b></td></tr>"))
                Case ListItemType.Item
                    ph.Controls.Add(New LiteralControl("<tr><td>"))
                    ph.Controls.Add(item1)
                    ph.Controls.Add(New LiteralControl("</td><td>"))
                    ph.Controls.Add(item2)
                    ph.Controls.Add(New LiteralControl("</td></tr>"))
                    AddHandler ph.DataBinding, New EventHandler(AddressOf Item_DataBinding)
                Case ListItemType.AlternatingItem
                    ph.Controls.Add(New LiteralControl("<tr bgcolor=""lightblue""><td>"))
                    ph.Controls.Add(item1)
                    ph.Controls.Add(New LiteralControl("</td><td>"))
                    ph.Controls.Add(item2)
                    ph.Controls.Add(New LiteralControl("</td></tr>"))
                    AddHandler ph.DataBinding, New EventHandler(AddressOf Item_DataBinding)
                Case ListItemType.Footer
                    ph.Controls.Add(New LiteralControl("</table>"))
            End Select
            container.Controls.Add(ph)
        End Sub
    End Class
    
    public class MyTemplate : System.Web.UI.ITemplate
    {
        System.Web.UI.WebControls.ListItemType templateType;
        public MyTemplate(System.Web.UI.WebControls.ListItemType type)
        {
            templateType = type;
        }
    
        public void InstantiateIn(System.Web.UI.Control container)
        {
            PlaceHolder ph = new PlaceHolder();
            Label item1 = new Label();
            Label item2 = new Label();
            item1.ID = "item1";
            item2.ID = "item2";
    
            switch (templateType)
            {
                case ListItemType.Header:
                    ph.Controls.Add(new LiteralControl("<table border=\"1\">" +
                        "<tr><td><b>Category ID</b></td>" + 
                        "<td><b>Category Name</b></td></tr>"));
                    break;
                case ListItemType.Item:
                    ph.Controls.Add(new LiteralControl("<tr><td>"));
                    ph.Controls.Add(item1);
                    ph.Controls.Add(new LiteralControl("</td><td>"));
                    ph.Controls.Add(item2);
                    ph.Controls.Add(new LiteralControl("</td></tr>"));
                    ph.DataBinding += new EventHandler(Item_DataBinding);
                    break;                    
                case ListItemType.AlternatingItem:
                    ph.Controls.Add(new LiteralControl("<tr bgcolor=\"lightblue\"><td>"));
                    ph.Controls.Add(item1);
                    ph.Controls.Add(new LiteralControl("</td><td>"));
                    ph.Controls.Add(item2);
                    ph.Controls.Add(new LiteralControl("</td></tr>"));
                    ph.DataBinding += new EventHandler(Item_DataBinding);
                    break;
                case ListItemType.Footer:
                    ph.Controls.Add(new LiteralControl("</table>"));
                    break;
            }
            container.Controls.Add(ph);
        }
    }
    

DataBinding イベントのハンドラを作成するには

  1. テンプレート クラスの一部であり、そのクラスの他のメソッド (たとえば InstantiateIn) のピアであるメソッドを作成します。またはページの静的メソッド (Visual Basic の場合 Shared) を作成します。ハンドラの名前は、以前にイベントを連結したときに使用した名前と一致させる必要があります。

  2. 次の操作を行って、データが含まれる DataItem オブジェクトへの参照を取得します。

    1. テンプレート項目の参照を取得します。これは、コントロールの NamingContainer プロパティから取得できます。

    2. 参照を使用して、名前付けコンテナの (テンプレート項目の) DataItem プロパティを取得します。

    3. DataItem オブジェクトから個々のデータ要素を抽出し、このデータ要素を使用してバインドするコントロールのプロパティを設定します。

    動的テンプレート内でデータ バインディングを行う 1 つの方法のコード例を次に示します。これは、PlaceHolder コントロールの場合と、前のプロシージャで作成した Literal コントロールと Label の場合の完全なデータ バインディング イベント ハンドラの例です。イベント ハンドラは、ページの静的メソッドとして実装されます。

    Shared Sub Item_DataBinding(ByVal sender As Object, ByVal e As System.EventArgs)
        Dim ph As PlaceHolder = CType(sender, PlaceHolder)
        Dim ri As RepeaterItem = CType(ph.NamingContainer, RepeaterItem)
        Dim item1Value As Integer = _
            Convert.ToInt32(DataBinder.Eval(ri.DataItem, "CategoryID"))
        Dim item2Value As String = _
            Convert.ToString(DataBinder.Eval(ri.DataItem, "CategoryName"))
        CType(ph.FindControl("item1"), Label).Text = item1Value.ToString()
        CType(ph.FindControl("item2"), Label).Text = item2Value
    End Sub
    
    static void Item_DataBinding(object sender, System.EventArgs e)
    {
        PlaceHolder ph = (PlaceHolder)sender;
        RepeaterItem ri = (RepeaterItem)ph.NamingContainer;
        Int32 item1Value = (Int32)DataBinder.Eval(ri.DataItem, "CategoryID");
        String item2Value = (String)DataBinder.Eval(ri.DataItem, "CategoryName");
        ((Label)ph.FindControl("item1")).Text = item1Value.ToString();
        ((Label)ph.FindControl("item2")).Text = item2Value;
    }
    

動的テンプレートの使用

動的テンプレートを使用すると、コード内でテンプレートをインスタンス化できます。

動的テンプレートを使用するには

  1. 動的テンプレートのインスタンスを作成し、適切な場合は項目型の値をテンプレートに渡します。

  2. このインスタンスを、テンプレート コントロールのテンプレート プロパティ (ItemTemplate、AlternatingItemTemplate、HeaderTemplate など) の 1 つに割り当てます。

    動的テンプレートを Repeater コントロールと共に使用する方法を次のコード例に示します。この例では、ページが読み込まれている間でコントロールがそのデータ ソースに連結される前に、テンプレートがインスタンス化されます。

    下記の例は、Microsoft SQL Server 7.0 以降で Northwind サンプル データベースに接続できることを前提としています。Categories テーブルのレコード一覧を返します。

    Protected Sub Page_Load(ByVal sender As Object, _
        ByVal e As System.EventArgs) Handles MyBase.Load
    
        Dim conn As New System.Data.SqlClient.SqlConnection( _
            ConfigurationManager.ConnectionStrings("Northwind").ConnectionString)
    
        Dim sqlDataAdapter1 As System.Data.SqlClient.SqlDataAdapter
        Dim dsCategories1 As System.Data.DataSet
    
        sqlDataAdapter1 = New System.Data.SqlClient.SqlDataAdapter( _
            "SELECT [CategoryID], [CategoryName] FROM [Categories]", conn)
        dsCategories1 = New System.Data.DataSet()
    
        Repeater1.HeaderTemplate = New MyTemplate(ListItemType.Header)
        Repeater1.ItemTemplate = New MyTemplate(ListItemType.Item)
        Repeater1.AlternatingItemTemplate = New MyTemplate(ListItemType.AlternatingItem)
        Repeater1.FooterTemplate = New MyTemplate(ListItemType.Footer)
        sqlDataAdapter1.Fill(dsCategories1, "Categories")
        Repeater1.DataSource = dsCategories1.Tables("Categories")
        Repeater1.DataBind()
    
    End Sub
    
    protected void Page_Load(object sender, EventArgs e)
    {
        System.Data.SqlClient.SqlConnection conn =
            new System.Data.SqlClient.SqlConnection(
            ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString);
    
        System.Data.SqlClient.SqlDataAdapter sqlDataAdapter1;
        System.Data.DataSet dsCategories1;
    
        sqlDataAdapter1 = new System.Data.SqlClient.SqlDataAdapter(
            "SELECT [CategoryID], [CategoryName] FROM [Categories]", conn);
        dsCategories1 = new System.Data.DataSet();
    
        Repeater1.HeaderTemplate = new MyTemplate(ListItemType.Header);
        Repeater1.ItemTemplate = new MyTemplate(ListItemType.Item);
        Repeater1.AlternatingItemTemplate =
           new MyTemplate(ListItemType.AlternatingItem);
        Repeater1.FooterTemplate = new MyTemplate(ListItemType.Footer);
        sqlDataAdapter1.Fill(dsCategories1, "Categories");
        Repeater1.DataSource = dsCategories1.Tables["Categories"];
        Repeater1.DataBind();
    }
    

完成した例の実行

前述したすべてのコンポーネントを作成した後は、Repeater1 という Repeater コントロールをページのマークアップに追加し、ページを実行します。Web ページの完成したコードとマークアップを次に示します (単一ファイルのコード モデルを使用)。

<%@ Page Language="VB" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

    Public Class MyTemplate
        Implements System.Web.UI.ITemplate

        Dim templateType As ListItemType

        Sub New(ByVal type As ListItemType)
            templateType = type
        End Sub

        Public Sub InstantiateIn(ByVal container As System.Web.UI.Control) _
          Implements System.Web.UI.ITemplate.InstantiateIn

            Dim ph As New PlaceHolder()
            Dim item1 As New Label()
            Dim item2 As New Label()
            item1.ID = "item1"
            item2.ID = "item2"

            Select Case (templateType)
                Case ListItemType.Header
                    ph.Controls.Add(New LiteralControl("<table border=""1"">" & _
                        "<tr><td><b>Category ID</b></td>" & _
                        "<td><b>Category Name</b></td></tr>"))
                Case ListItemType.Item
                    ph.Controls.Add(New LiteralControl("<tr><td>"))
                    ph.Controls.Add(item1)
                    ph.Controls.Add(New LiteralControl("</td><td>"))
                    ph.Controls.Add(item2)
                    ph.Controls.Add(New LiteralControl("</td></tr>"))
                    AddHandler ph.DataBinding, New EventHandler(AddressOf Item_DataBinding)
                Case ListItemType.AlternatingItem
                    ph.Controls.Add(New LiteralControl("<tr bgcolor=""lightblue""><td>"))
                    ph.Controls.Add(item1)
                    ph.Controls.Add(New LiteralControl("</td><td>"))
                    ph.Controls.Add(item2)
                    ph.Controls.Add(New LiteralControl("</td></tr>"))
                    AddHandler ph.DataBinding, New EventHandler(AddressOf Item_DataBinding)
                Case ListItemType.Footer
                    ph.Controls.Add(New LiteralControl("</table>"))
            End Select
            container.Controls.Add(ph)
        End Sub
    End Class
    Shared Sub Item_DataBinding(ByVal sender As Object, ByVal e As System.EventArgs)
        Dim ph As PlaceHolder = CType(sender, PlaceHolder)
        Dim ri As RepeaterItem = CType(ph.NamingContainer, RepeaterItem)
        Dim item1Value As Integer = _
            Convert.ToInt32(DataBinder.Eval(ri.DataItem, "CategoryID"))
        Dim item2Value As String = _
            Convert.ToString(DataBinder.Eval(ri.DataItem, "CategoryName"))
        CType(ph.FindControl("item1"), Label).Text = item1Value.ToString()
        CType(ph.FindControl("item2"), Label).Text = item2Value
    End Sub

    Protected Sub Page_Load(ByVal sender As Object, _
        ByVal e As System.EventArgs) Handles MyBase.Load

        Dim conn As New System.Data.SqlClient.SqlConnection( _
            ConfigurationManager.ConnectionStrings("Northwind").ConnectionString)

        Dim sqlDataAdapter1 As System.Data.SqlClient.SqlDataAdapter
        Dim dsCategories1 As System.Data.DataSet

        sqlDataAdapter1 = New System.Data.SqlClient.SqlDataAdapter( _
            "SELECT [CategoryID], [CategoryName] FROM [Categories]", conn)
        dsCategories1 = New System.Data.DataSet()

        Repeater1.HeaderTemplate = New MyTemplate(ListItemType.Header)
        Repeater1.ItemTemplate = New MyTemplate(ListItemType.Item)
        Repeater1.AlternatingItemTemplate = New MyTemplate(ListItemType.AlternatingItem)
        Repeater1.FooterTemplate = New MyTemplate(ListItemType.Footer)
        sqlDataAdapter1.Fill(dsCategories1, "Categories")
        Repeater1.DataSource = dsCategories1.Tables("Categories")
        Repeater1.DataBind()

    End Sub

</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Dynamically Creating Templates</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
      <asp:Repeater id="Repeater1" runat="server"></asp:Repeater>    
    </div>
    </form>
</body>
</html>
<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

    public class MyTemplate : System.Web.UI.ITemplate
    {
        System.Web.UI.WebControls.ListItemType templateType;
        public MyTemplate(System.Web.UI.WebControls.ListItemType type)
        {
            templateType = type;
        }

        public void InstantiateIn(System.Web.UI.Control container)
        {
            PlaceHolder ph = new PlaceHolder();
            Label item1 = new Label();
            Label item2 = new Label();
            item1.ID = "item1";
            item2.ID = "item2";

            switch (templateType)
            {
                case ListItemType.Header:
                    ph.Controls.Add(new LiteralControl("<table border=\"1\">" +
                        "<tr><td><b>Category ID</b></td>" + 
                        "<td><b>Category Name</b></td></tr>"));
                    break;
                case ListItemType.Item:
                    ph.Controls.Add(new LiteralControl("<tr><td>"));
                    ph.Controls.Add(item1);
                    ph.Controls.Add(new LiteralControl("</td><td>"));
                    ph.Controls.Add(item2);
                    ph.Controls.Add(new LiteralControl("</td></tr>"));
                    ph.DataBinding += new EventHandler(Item_DataBinding);
                    break;                    
                case ListItemType.AlternatingItem:
                    ph.Controls.Add(new LiteralControl("<tr bgcolor=\"lightblue\"><td>"));
                    ph.Controls.Add(item1);
                    ph.Controls.Add(new LiteralControl("</td><td>"));
                    ph.Controls.Add(item2);
                    ph.Controls.Add(new LiteralControl("</td></tr>"));
                    ph.DataBinding += new EventHandler(Item_DataBinding);
                    break;
                case ListItemType.Footer:
                    ph.Controls.Add(new LiteralControl("</table>"));
                    break;
            }
            container.Controls.Add(ph);
        }
    }

    static void Item_DataBinding(object sender, System.EventArgs e)
    {
        PlaceHolder ph = (PlaceHolder)sender;
        RepeaterItem ri = (RepeaterItem)ph.NamingContainer;
        Int32 item1Value = (Int32)DataBinder.Eval(ri.DataItem, "CategoryID");
        String item2Value = (String)DataBinder.Eval(ri.DataItem, "CategoryName");
        ((Label)ph.FindControl("item1")).Text = item1Value.ToString();
        ((Label)ph.FindControl("item2")).Text = item2Value;
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        System.Data.SqlClient.SqlConnection conn =
            new System.Data.SqlClient.SqlConnection(
            ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString);

        System.Data.SqlClient.SqlDataAdapter sqlDataAdapter1;
        System.Data.DataSet dsCategories1;

        sqlDataAdapter1 = new System.Data.SqlClient.SqlDataAdapter(
            "SELECT [CategoryID], [CategoryName] FROM [Categories]", conn);
        dsCategories1 = new System.Data.DataSet();

        Repeater1.HeaderTemplate = new MyTemplate(ListItemType.Header);
        Repeater1.ItemTemplate = new MyTemplate(ListItemType.Item);
        Repeater1.AlternatingItemTemplate =
           new MyTemplate(ListItemType.AlternatingItem);
        Repeater1.FooterTemplate = new MyTemplate(ListItemType.Footer);
        sqlDataAdapter1.Fill(dsCategories1, "Categories");
        Repeater1.DataSource = dsCategories1.Tables["Categories"];
        Repeater1.DataBind();
    }


</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Dynamically Creating Templates</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
      <asp:Repeater id="Repeater1" runat="server"></asp:Repeater>
    </div>
    </form>
</body>
</html>

参照

その他の技術情報

ASP.NET Web サーバー コントロールの操作