Практические руководство. Динамическое создание шаблонов серверных веб-элементов управления ASP.NET
Обновлен: Ноябрь 2007
При работе с шаблонами элементов управления до времени выполнения может быть неизвестно, какие шаблоны нужны или какой текст и элементы управления должен содержать шаблон. В этом случае можно создать шаблон динамически в коде.
![]() |
---|
Также существует возможность создания шаблонов как пользовательских элементов управления и их динамической привязки к элементам управления на странице. Дополнительные сведения см. в разделе Практическое руководство. Создание пользовательских элементов управления-шаблонов ASP.NET. |
Создание шаблонов в коде возможно для всех элементов управления, использующих шаблоны: DataList, Repeater, GridView, FormView, DetailsView и другие. В элементе управления GridView используются шаблоны с определением столбцов, а не шаблоны со строчной структурой, как в других элементах управления.
![]() |
---|
По сравнению с другими шаблонными элементами управления при создании столбцов шаблонов для элемента управления GridView присутствует ряд отличий. Дополнительные сведения см. в разделе Создание пользовательского столбца в серверном веб-элементе управления GridView. |
Создание класса шаблона
Чтобы создать динамические шаблоны, необходимо создать класс шаблона, для которого при необходимости можно создать экземпляр.
Чтобы создать класс шаблона
Создайте новый класс, реализующий интерфейс System.Web.UI.ITemplate.
При необходимости передайте в конструктор класса значение, используемое классом для определения типа создаваемого шаблона (ItemTemplate, AlternatingItemTemplate и т. п.).
Примечание.
Строго типизированным способом передачи типа шаблона конструктору является добавление к конструктору параметра с типом ListItemType. Перечисление ListItemType определяет возможные типы шаблонов для элементов управления Repeater, DataList и других элементов управления со списками.
В классе реализуйте метод InstantiateIn (член интерфейса ITemplate).
Этот метод предоставляет способ вставки экземпляра текста и элементов управления в указанный контейнер.
Создайте элементы управления для шаблона в методе InstantiateIn, задайте их свойства, а затем добавьте их в родительскую коллекцию Controls.
Доступ к родительскому элементу управления можно получить с помощью ссылки, передаваемой методу InstantiateIn.
Примечание.
Нельзя непосредственно добавить статический текст в коллекцию Controls, но можно создать элементы управления Literal или LiteralControl, задать их свойства Text, а затем добавить эти элементы управления в родительскую коллекцию.
Для элементов управления, требующих привязки к данным, необходимо создать и привязать метод для обработки события элемента управления DataBinding. Это событие будет инициировано после создания шаблона со всеми его элементами управления. Событие предоставляет возможность извлечения данных и использования их в элементе управления.
Примечание.
Невозможно добавить выражение привязки данных в качестве строки в шаблон, как это происходит при определении шаблонов в режиме разработки, поскольку выражения привязки данных преобразуются в код на стадии обработки страницы (до создания шаблона).
В обработчике событий DataBinding имеется возможность изменить содержимое элемента управления. Обычно (но не обязательно) данные откуда-то извлекаются и присваиваются свойству Text данного элемента управления (или другому свойству).
Примечание.
Информацию о привязке данных для веб-страниц ASP.NET см. в Доступ к данным с помощью ASP.NET.
Чтобы добавить привязку данных к динамическому шаблону, необходимо выполнить следующие действия:
Добавьте обработчик событий привязки данных для элементов управления, создаваемых в шаблоне.
Создайте обработчик, к которому выполняется привязка. В обработчике получите данные, к которым следует выполнить привязку, и присвойте их соответствующему свойству привязываемого элемента управления.
Примечание.
При наличии в шаблонах нескольких типов элементов управления необходимо создать отдельный обработчик событий привязки данных для каждого типа элемента управления.
Следующий пример кода иллюстрирует класс шаблона с именем 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
Создайте метод, являющийся либо частью класса шаблона и является одноранговым классом других методов класса (таких как InstantiateIn), либо статическим методом (Shared в Visual Basic) страницы. Имя обработчика должно соответствовать имени, используемому ранее при привязке события.
Получите ссылку на объект DataItem, содержащий данные, следующим образом:
Получите ссылку на элемент шаблона, например, из свойства элемента управления NamingContainer.
Используйте эту ссылку для получения свойства DataItem контейнера имен (элемента шаблона).
Извлеките отдельный элемент данных (например, столбец с данными) из объекта 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; }
Применение динамического шаблона
Теперь, когда доступен динамический шаблон, можно создать его экземпляр в коде.
Чтобы использовать динамический шаблон
Создайте экземпляр динамического шаблона, передав ему соответствующее значение типа элемента.
Привяжите экземпляр к одному из свойств шаблонного элемента управления, такому как 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>