HOW TO:動態建立 ASP.NET Web 伺服器控制項樣板
更新:2007 年 11 月
在處理樣板化的控制項時,您可能無法在執行階段之前得知所需要的樣板 (Template),或是樣板中應包含哪些文字或控制項。在這種情況下,可以在程式碼中動態建立樣板。
![]() |
---|
也可以將樣板建立為使用者控制項 (User Control),並以動態方式將它們繫結至網頁上的控制項。如需詳細資訊,請參閱 HOW TO:建立樣板化 ASP.NET 使用者控制項。 |
您可以為所有使用樣板的控制項在程式碼中建立樣板:DataList、Repeater、GridView、FormView、DetailsView 和更多。對於 GridView 控制項,使用樣板定義資料行,而不像其他控制項,使用資料列配置的樣板。
![]() |
---|
與其他樣板化的控制項相比,為 GridView 控制項建立樣板控制項時會有一些差異。如需詳細資訊,請參閱建立 GridView Web 伺服器控制項中的自訂資料行。 |
建立樣板類別
若要建立動態樣板,您必須建立樣板類別,這樣在之後就可以在需要時加以具現化。
若要建立樣板類別
建立實作 System.Web.UI.ITemplate 介面的新類別。
也可以選擇將值傳遞到類別的建構函式 (Constructor) 中,類別可用該值判斷要建立的樣板型別 (ItemTemplate、AlternatingItemTemplate 等等)。
注意事項:
將樣板型別傳遞至建構函式的型別安全方式,是使用 ListItemType 型別將參數加入至建構函式。ListItemType 列舉型別 (Enumeration) 會為 Repeater、DataList 和其他清單控制項定義可能的樣板型別。
在類別中實作 InstantiateIn 方法,這是 ITemplate 介面的成員。
這個方法可提供將文字和控制項的執行個體 (Instance) 插入到指定容器 (Container) 中的方式。
在 InstantiateIn 方法中,建立樣板項目的控制項、設定其屬性,再將這些控制項加入至父代 (Parent) 的 Controls 集合中。
您可以透過傳遞至 InstantiateIn 方法中的參考,存取父控制項。
注意事項:
您無法直接將靜態 (Static) 文字加入至 Controls 集合,但可以建立如同 Literal 控制項或 LiteralControl 控制項的控制項、設定其 Text 屬性,然後將這些控制項加入至父集合。
對需要資料繫結的控制項,建立並繫結方法,以便處理控制項的 DataBinding 事件。使用所有控制項建立樣板項目後會引發這個事件,此事件也提供您擷取資料,並將該資料用在控制項的機會。
注意事項:
如同在設計階段定義樣板的方式一樣,當您在樣板中建立控制項時,無法將資料繫結運算式視為字串嵌入,這是由於在樣板建立前,資料繫結運算式已轉換成程式碼之故。
您在 DataBinding 事件的處理常式中,有機會管理控制項內容。通常 (但不一定),您會從某個位置擷取資料,並將資料指派給控制項的 Text 屬性 (或其他屬性)。
注意事項:
如需在 ASP.NET Web 網頁中進行資料繫結的詳細資訊,請參閱使用 ASP.NET 存取資料。
若要將資料繫結加入至動態樣板,必須執行以下各項:
將資料繫結事件處理常式加入至您在樣板中建立的控制項中。
建立要繫結的處理常式。在處理常式中,取得要繫結的資料,將其指派給正在繫結控制項的合適屬性。
注意事項:
如果樣板中有多個控制項型別時,則您必須為每個控制項型別建立不同的資料繫結事件處理常式。
下列程式碼範例說明的是實作 ITemplate 介面的樣板類別,其名稱為 MyTemplate。MyTemplate 類別會定義接受 ListItemType 列舉值的建構函式,以表示建立的是何種樣板。根據樣板型別,程式碼會建立各種控制項並將它們加入至 PlaceHolder 控制項 (而之後會將這個控制項加入至父控制項的 Controls 集合),並針對 Item 和 AlternatingItem 的 ListItemType,建立名為 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 事件建立事件處理常式
建立一個屬於樣板類別並與類別之其他方法同等的方法 (例如 InstantiateIn),或是網頁的靜態 (在 Visual Basic 中為 Shared) 方法。處理常式的名稱必須符合您稍早用來繫結事件的名稱。
藉由執行下列動作,取得含有資料之 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 控制項搭配使用。在這個範例中,樣板是在網頁載入中而控制項繫結到其資料來源之前具現化。
下列範例假設您可以連接至 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>