HOW TO:動態建立 ASP.NET Web 伺服器控制項樣板

更新:2007 年 11 月

在處理樣板化的控制項時,您可能無法在執行階段之前得知所需要的樣板 (Template),或是樣板中應包含哪些文字或控制項。在這種情況下,可以在程式碼中動態建立樣板。

注意事項:

也可以將樣板建立為使用者控制項 (User Control),並以動態方式將它們繫結至網頁上的控制項。如需詳細資訊,請參閱 HOW TO:建立樣板化 ASP.NET 使用者控制項

您可以為所有使用樣板的控制項在程式碼中建立樣板:DataListRepeaterGridViewFormViewDetailsView 和更多。對於 GridView 控制項,使用樣板定義資料行,而不像其他控制項,使用資料列配置的樣板。

注意事項:

與其他樣板化的控制項相比,為 GridView 控制項建立樣板控制項時會有一些差異。如需詳細資訊,請參閱建立 GridView Web 伺服器控制項中的自訂資料行

建立樣板類別

若要建立動態樣板,您必須建立樣板類別,這樣在之後就可以在需要時加以具現化。

若要建立樣板類別

  1. 建立實作 System.Web.UI.ITemplate 介面的新類別。

  2. 也可以選擇將值傳遞到類別的建構函式 (Constructor) 中,類別可用該值判斷要建立的樣板型別 (ItemTemplate、AlternatingItemTemplate 等等)。

    注意事項:

    將樣板型別傳遞至建構函式的型別安全方式,是使用 ListItemType 型別將參數加入至建構函式。ListItemType 列舉型別 (Enumeration) 會為 RepeaterDataList 和其他清單控制項定義可能的樣板型別。

  3. 在類別中實作 InstantiateIn 方法,這是 ITemplate 介面的成員。

    這個方法可提供將文字和控制項的執行個體 (Instance) 插入到指定容器 (Container) 中的方式。

  4. InstantiateIn 方法中,建立樣板項目的控制項、設定其屬性,再將這些控制項加入至父代 (Parent) 的 Controls 集合中。

    您可以透過傳遞至 InstantiateIn 方法中的參考,存取父控制項。

    注意事項:

    您無法直接將靜態 (Static) 文字加入至 Controls 集合,但可以建立如同 Literal 控制項或 LiteralControl 控制項的控制項、設定其 Text 屬性,然後將這些控制項加入至父集合。

  5. 對需要資料繫結的控制項,建立並繫結方法,以便處理控制項的 DataBinding 事件。使用所有控制項建立樣板項目後會引發這個事件,此事件也提供您擷取資料,並將該資料用在控制項的機會。

    注意事項:

    如同在設計階段定義樣板的方式一樣,當您在樣板中建立控制項時,無法將資料繫結運算式視為字串嵌入,這是由於在樣板建立前,資料繫結運算式已轉換成程式碼之故。

    您在 DataBinding 事件的處理常式中,有機會管理控制項內容。通常 (但不一定),您會從某個位置擷取資料,並將資料指派給控制項的 Text 屬性 (或其他屬性)。

    注意事項:

    如需在 ASP.NET Web 網頁中進行資料繫結的詳細資訊,請參閱使用 ASP.NET 存取資料

    若要將資料繫結加入至動態樣板,必須執行以下各項:

    • 將資料繫結事件處理常式加入至您在樣板中建立的控制項中。

    • 建立要繫結的處理常式。在處理常式中,取得要繫結的資料,將其指派給正在繫結控制項的合適屬性。

      注意事項:

      如果樣板中有多個控制項型別時,則您必須為每個控制項型別建立不同的資料繫結事件處理常式。

    下列程式碼範例說明的是實作 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 物件中擷取個別資料項目,並用來設定所繫結之控制項的屬性。

    下列程式碼範例會說明在動態樣板中執行資料繫結的方法。它會為 PlaceHolder 控制項和前面程序所建立的 LiteralLabel 控制項顯示完整的資料繫結事件處理常式。事件處理常式是實作為網頁的靜態方法。

    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 屬性。

    下列程式碼範例會顯示如何將動態樣板與 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 >

    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 >
    <title>Dynamically Creating Templates</title>
</head>
<body>
    <form id="form1" >
    <div>
      <asp:Repeater id="Repeater1" ></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 >

    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 >
    <title>Dynamically Creating Templates</title>
</head>
<body>
    <form id="form1" >
    <div>
      <asp:Repeater id="Repeater1" ></asp:Repeater>
    </div>
    </form>
</body>
</html>

請參閱

其他資源

使用 ASP.NET Web 伺服器控制項