Поделиться через


Практические руководство. Динамическое создание шаблонов серверных веб-элементов управления ASP.NET

Обновлен: Ноябрь 2007

При работе с шаблонами элементов управления до времени выполнения может быть неизвестно, какие шаблоны нужны или какой текст и элементы управления должен содержать шаблон. В этом случае можно создать шаблон динамически в коде.

0e39s2ck.alert_note(ru-ru,VS.90).gifПримечание.

Также существует возможность создания шаблонов как пользовательских элементов управления и их динамической привязки к элементам управления на странице. Дополнительные сведения см. в разделе Практическое руководство. Создание пользовательских элементов управления-шаблонов ASP.NET.

Создание шаблонов в коде возможно для всех элементов управления, использующих шаблоны: DataList, Repeater, GridView, FormView, DetailsView и другие. В элементе управления GridView используются шаблоны с определением столбцов, а не шаблоны со строчной структурой, как в других элементах управления.

0e39s2ck.alert_note(ru-ru,VS.90).gifПримечание.

По сравнению с другими шаблонными элементами управления при создании столбцов шаблонов для элемента управления GridView присутствует ряд отличий. Дополнительные сведения см. в разделе Создание пользовательского столбца в серверном веб-элементе управления GridView.

Создание класса шаблона

Чтобы создать динамические шаблоны, необходимо создать класс шаблона, для которого при необходимости можно создать экземпляр.

Чтобы создать класс шаблона

  1. Создайте новый класс, реализующий интерфейс System.Web.UI.ITemplate.

  2. При необходимости передайте в конструктор класса значение, используемое классом для определения типа создаваемого шаблона (ItemTemplate, AlternatingItemTemplate и т. п.).

    0e39s2ck.alert_note(ru-ru,VS.90).gifПримечание.

    Строго типизированным способом передачи типа шаблона конструктору является добавление к конструктору параметра с типом ListItemType. Перечисление ListItemType определяет возможные типы шаблонов для элементов управления Repeater, DataList и других элементов управления со списками.

  3. В классе реализуйте метод InstantiateIn (член интерфейса ITemplate).

    Этот метод предоставляет способ вставки экземпляра текста и элементов управления в указанный контейнер.

  4. Создайте элементы управления для шаблона в методе InstantiateIn, задайте их свойства, а затем добавьте их в родительскую коллекцию Controls.

    Доступ к родительскому элементу управления можно получить с помощью ссылки, передаваемой методу InstantiateIn.

    0e39s2ck.alert_note(ru-ru,VS.90).gifПримечание.

    Нельзя непосредственно добавить статический текст в коллекцию Controls, но можно создать элементы управления Literal или LiteralControl, задать их свойства Text, а затем добавить эти элементы управления в родительскую коллекцию.

  5. Для элементов управления, требующих привязки к данным, необходимо создать и привязать метод для обработки события элемента управления DataBinding. Это событие будет инициировано после создания шаблона со всеми его элементами управления. Событие предоставляет возможность извлечения данных и использования их в элементе управления.

    0e39s2ck.alert_note(ru-ru,VS.90).gifПримечание.

    Невозможно добавить выражение привязки данных в качестве строки в шаблон, как это происходит при определении шаблонов в режиме разработки, поскольку выражения привязки данных преобразуются в код на стадии обработки страницы (до создания шаблона).

    В обработчике событий DataBinding имеется возможность изменить содержимое элемента управления. Обычно (но не обязательно) данные откуда-то извлекаются и присваиваются свойству Text данного элемента управления (или другому свойству).

    0e39s2ck.alert_note(ru-ru,VS.90).gifПримечание.

    Информацию о привязке данных для веб-страниц ASP.NET см. в Доступ к данным с помощью ASP.NET.

    Чтобы добавить привязку данных к динамическому шаблону, необходимо выполнить следующие действия:

    • Добавьте обработчик событий привязки данных для элементов управления, создаваемых в шаблоне.

    • Создайте обработчик, к которому выполняется привязка. В обработчике получите данные, к которым следует выполнить привязку, и присвойте их соответствующему свойству привязываемого элемента управления.

      0e39s2ck.alert_note(ru-ru,VS.90).gifПримечание.

      При наличии в шаблонах нескольких типов элементов управления необходимо создать отдельный обработчик событий привязки данных для каждого типа элемента управления.

    Следующий пример кода иллюстрирует класс шаблона с именем MyTemplate, который реализует интерфейс ITemplate. Класс MyTemplate определяет конструктор, получающий значение из перечисления ListItemType, которое указывает тип создаваемого шаблона. В зависимости от типа создаваемого шаблона код создает другие типы элементов управления и добавляет их в элемент управления PlaceHolder, который затем добавляется в коллекцию Controls родительского элемента управления. Для перечисления ListItemType элементов Item и AlternatingItem создается обработчик событий с именем 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), либо статическим методом (Shared в Visual Basic) страницы. Имя обработчика должно соответствовать имени, используемому ранее при привязке события.

  2. Получите ссылку на объект DataItem, содержащий данные, следующим образом:

    1. Получите ссылку на элемент шаблона, например, из свойства элемента управления NamingContainer.

    2. Используйте эту ссылку для получения свойства DataItem контейнера имен (элемента шаблона).

    3. Извлеките отдельный элемент данных (например, столбец с данными) из объекта DataItemи используйте его для задания свойства привязываемого элемента управления.

    В приведенном ниже коде показан один способ выполнения привязки данных в динамическом шаблоне. Он показывает полный обработчик событий с привязкой к данным для элемента управления 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.

    В приведенном ниже примере показано использование динамического шаблона с элементом управления Repeater. В этом примере экземпляры из шаблонов создаются при загрузке страницы и перед привязкой этого элемента управления к его источнику данных.

    Пример, представленный ниже, подразумевает возможность соединения с учебной базой данных Northwind Microsoft SQL Server версии 7.0 или более поздней. Он возвращает список записей из таблицы 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();
    }
    

Выполнение полного примера

После создания всех компонентов, приведенных ранее, необходимо добавить элемент управления Repeater с именем Repeater1 к разметке страницы и запустить страницу. Полный код и разметка для веб-страницы (с использованием однофайловой модели кода) показаны ниже.

<%@ 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