如何:动态创建 ASP.NET Web 服务器控件模板

更新:2007 年 11 月

在使用模板化控件时,您可能直到运行时才知道需要什么模板或模板中应包含哪些文本或控件。在这种情况下,您可以在代码中动态创建模板。

0e39s2ck.alert_note(zh-cn,VS.90).gif说明:

还可以将模板创建为用户控件,并将其动态绑定到页上的控件。有关详细信息,请参见如何:创建模板化的 ASP.NET 用户控件

您可以在代码中为所有使用模板的控件(DataListRepeaterGridViewFormViewDetailsView 及其他)创建模板。对于 GridView 控件,您要使用的是定义列的模板,而不是其他控件的行布局模板。

0e39s2ck.alert_note(zh-cn,VS.90).gif说明:

与其他模板化控件相比,在为 GridView 控件创建模板列时,有一些不同之处。有关详细信息,请参见在 GridView Web 服务器控件中创建自定义列

创建模板类

若要创建动态模板,请创建模板类,然后在需要时实例化该类。

创建模板类

  1. 创建实现 System.Web.UI.ITemplate 接口的新类。

  2. 您也可以将值传递到类的构造函数,类可以使用该值来确定要创建的模板类型(ItemTemplate、AlternatingItemTemplate 等)。

    0e39s2ck.alert_note(zh-cn,VS.90).gif说明:

    将模板类型传递到构造函数的类型安全方法是向构造函数添加类型为 ListItemType 的参数。ListItemType 枚举为 RepeaterDataList 和其他列表控件定义可能的模板类型。

  3. 在类中,实现 InstantiateIn 方法,该方法是 ITemplate 接口的成员。

    此方法提供将文本实例和控件实例插入指定容器的方法。

  4. InstantiateIn 方法中,为模板项创建控件,设置其属性,然后将它们添加到父级的 Controls 集合。

    您可以通过传递到 InstantiateIn 方法的引用访问父控件。

    0e39s2ck.alert_note(zh-cn,VS.90).gif说明:

    不能直接向 Controls 集合添加静态文本,但可以创建类似 Literal 控件或 LiteralControl 控件的控件,设置它们的 Text 属性,然后向父集合添加这些控件。

  5. 对需要数据绑定的控件,创建并绑定方法以处理控件的 DataBinding 事件。在创建了模板项及其所有控件后,会引发此事件,这样您就有机会获取数据并在控件中使用数据。

    0e39s2ck.alert_note(zh-cn,VS.90).gif说明:

    在模板中创建控件时,不能像在设计时定义模板那样将数据绑定表达式作为字符串嵌入,因为数据绑定表达式会在创建模板之前转换为代码。

    DataBinding 事件的处理程序中,您有机会操作控件的内容。通常(并非一定),您从某处获取数据并将其分配给控件的 Text 属性(或其他属性)。

    0e39s2ck.alert_note(zh-cn,VS.90).gif说明:

    有关 ASP.NET 网页中的数据绑定的信息,请参见通过 ASP.NET 访问数据

    要将数据绑定添加到动态模板,必须执行如下操作:

    • 将数据绑定事件处理程序添加到您在模板中创建的控件。

    • 创建您要被绑定的处理程序。在该处理程序中,获取您要被绑定的数据并将其分配给要被绑定控件的相应属性。

      0e39s2ck.alert_note(zh-cn,VS.90).gif说明:

      如果在您的模板中具有多种类型的控件,您需要为每一种控件类型创建一个不同的数据绑定事件处理程序。

    下面的代码示例阐释一个用于实现 ITemplate 接口的名为 MyTemplate 的模板类。MyTemplate 类定义一个接受 ListItemType 枚举值以指示所创建的模板类型的构造函数。根据模板类型,该代码创建不同类型的控件并将这些控件添加到 PlaceHolder 控件中,然后将该控件添加到父控件的 Controls 集合中。对于 ItemAlternatingItemListItemType,创建了名为 Item_DataBinding 的事件处理程序。

    呈现的网页产生一个 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 控件添加到页面标记中并运行该页。下面显示了网页(使用单文件代码模型)的完整代码和标记。

<%@ 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 服务器控件