Gewusst wie: Dynamisches Erstellen von Vorlagen für ASP.NET-Webserversteuerelemente
Aktualisiert: November 2007
Bei der Verwendung von auf Vorlagen basierenden Steuerelementen kann möglicherweise erst zur Laufzeit festgestellt werden, welche Vorlagen erforderlich sind bzw. welchen Text oder welche Steuerelemente die Vorlage enthalten soll. In diesem Fall können Sie die Vorlagen dynamisch im Code erstellen.
Hinweis: |
---|
Sie können Vorlagen auch als Benutzersteuerelemente erstellen und diese dynamisch an die Steuerelemente der Seite binden. Ausführliche Informationen finden Sie unter Gewusst wie: Erstellen von vorlagenbasierten ASP.NET-Benutzersteuerelementen. |
Sie können Vorlagen im Quellcode für alle Steuerelemente erstellen, die Vorlagen verwenden, darunter: DataList, Repeater, GridView, FormView und DetailsView. Im Gegensatz zu den Vorlagen mit Zeilenlayout bei den anderen Steuerelementen verwenden Sie für das GridView-Steuerelement Vorlagen zum Definieren von Spalten.
Hinweis: |
---|
Bei der Erstellung von Vorlagenspalten für das GridView-Steuerelement sind im Vergleich zu anderen auf Vorlagen basierenden Steuerelementen einige Unterschiede zu beachten. Ausführliche Informationen finden Sie unter Erstellen einer benutzerdefinierten Spalte in einem GridView-Webserversteuerelement. |
Erstellen der Vorlagenklasse
Zum Erstellen dynamischer Vorlagen erstellen Sie eine Vorlagenklasse, die bei Bedarf instanziiert werden kann.
So erstellen Sie eine Vorlagenklasse
Erstellen Sie eine neue Klasse, die die System.Web.UI.ITemplate-Schnittstelle implementiert.
Übergeben Sie optional einen Wert an den Klassenkonstruktor, anhand dessen die Klasse den zu erstellenden Vorlagentyp bestimmen kann (ItemTemplate, AlternatingItemTemplate usw.).
Hinweis: Sie können den Vorlagentyp auf eine typsichere Weise an den Konstruktor übergeben, indem Sie dem Konstruktor einen Parameter des Typs ListItemType hinzufügen. In der ListItemType-Enumeration werden die möglichen Vorlagentypen für das Repeater-Listensteuerelement, das DataList-Listensteuerelement und andere Listensteuerelemente festgelegt.
Implementieren Sie in der Klasse die InstantiateIn-Methode, die ein Member der ITemplate-Schnittstelle ist.
Diese Methode bietet die Möglichkeit, dem angegebenen Container Instanzen des Textes und der Steuerelemente hinzuzufügen.
Erstellen Sie die Steuerelemente für das Vorlagenelement in der InstantiateIn-Methode, legen Sie deren Eigenschaften fest, und fügen Sie sie anschließend der übergeordneten Controls-Auflistung hinzu.
Mithilfe des an die InstantiateIn-Methode übergebenen Verweises können Sie auf das übergeordnete Steuerelement zugreifen.
Hinweis: Es ist nicht möglich, der Controls-Auflistung statischen Text direkt hinzuzufügen. Sie können jedoch ein Steuerelement erstellen (beispielsweise ein Literal-Steuerelement oder ein LiteralControl-Steuerelement), dessen Text-Eigenschaft festlegen und dieses Steuerelement dann der übergeordneten Auflistung hinzufügen.
Für Steuerelemente, die Datenbindung erfordern, erstellen und binden Sie eine Methode zur Behandlung des DataBinding-Ereignisses des Steuerelements. Dieses Ereignis wird ausgelöst, wenn das Vorlagenelement mit sämtlichen Steuerelementen erzeugt wurde, und es bietet Ihnen die Möglichkeit, die Daten abzurufen und in einem Steuerelement zu verwenden.
Hinweis: Beim Erstellen von Steuerelementen in der Vorlage kann ein Datenbindungsausdruck nicht als Zeichenfolge eingebettet werden wie es beim Definieren von Vorlagen zur Entwurfszeit möglich ist. Das liegt daran, dass Datenbindungsausdrücke in Code konvertiert werden, bevor die Vorlage erstellt wird.
Im Handler für das DataBinding-Ereignis können Sie die Inhalte des Steuerelements bearbeiten. Üblicherweise (aber nicht zwangsläufig) rufen Sie die Daten ab und weisen sie der Text-Eigenschaft (oder einer anderen Eigenschaft) des Steuerelements zu.
Hinweis: Weitere Informationen zur Datenbindung in ASP.NET-Webseiten finden Sie unter Zugreifen auf Daten mit ASP.NET.
Um einer dynamischen Vorlage die Datenbindung hinzuzufügen, führen Sie die folgenden Schritte aus:
Fügen Sie einen Ereignishandler für die Datenbindung zu den in der Vorlage erstellten Steuerelementen hinzu.
Erstellen Sie den Handler, mit dem Sie die Bindung herstellen möchten. Wählen Sie im Handler die zu bindenden Daten, und weisen Sie sie der entsprechenden Eigenschaft des Steuerelements zu.
Hinweis: Wenn in Ihren Vorlagen verschiedene Steuerelementtypen vorhanden sind, müssen Sie für jeden Typ einen anderen Datenbindungs-Ereignishandler erstellen.
Im folgenden Codebeispiel wird eine Vorlagenklasse mit dem Namen MyTemplate dargestellt, die die ITemplate-Schnittstelle implementiert. In der MyTemplate-Klasse wird ein Konstruktor definiert, der den Wert einer ListItemType-Enumeration entgegennimmt, um den erstellten Vorlagentyp anzugeben. In Abhängigkeit vom Vorlagentyp werden mithilfe des Codes verschiedene Steuerelementtypen erstellt und einem PlaceHolder-Steuerelement hinzugefügt. Anschließend wird das Steuerelement zur Controls-Auflistung der übergeordneten Steuerelemente hinzugefügt. Für ListItemType von Item und von AlternatingItem wird ein Ereignishandler mit dem Namen Item_DataBinding erstellt.
Die dargestellte Webseite enthält dadurch eine HTML-Tabelle mit einer anderen Hintergrundfarbe für jede zweite Elementvorlage.
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); } }
So erstellen Sie einen Handler für das DataBinding-Ereignis
Erstellen Sie entweder eine Methode, die Teil Ihrer Vorlagenklasse und Peer der anderen Klassenmethoden (wie z. B. InstantiateIn) ist, oder erstellen Sie eine statische (in Visual Basic Shared) Methode der Seite. Der Name des Handlers muss mit dem Namen übereinstimmen, den Sie zuvor bei der Ereignisbindung verwendet haben.
Rufen Sie einen Verweis auf das DataItem-Objekt ab, das die Daten enthält, indem Sie folgende Schritte ausführen:
Rufen Sie über die NamingContainer-Eigenschaft des Steuerelements einen Verweis auf das Vorlagenelement ab.
Verwenden Sie diesen Verweis, um die DataItem-Eigenschaft des Benennungscontainers (d. h. des Vorlagenelements) abzurufen.
Extrahieren Sie das einzelne Datenelement aus dem DataItem-Objekt, und verwenden Sie es, um eine Eigenschaft des zu bindenden Steuerelements festzulegen.
Im folgenden Codebeispiel wird eine Möglichkeit veranschaulicht, die Datenbindung innerhalb einer dynamischen Vorlage durchzuführen. Im Beispiel wird ein vollständiger Ereignishandler zur Datenbindung für das PlaceHolder-Steuerelement sowie für das Literal-Steuerelement und das Label-Steuerelement dargestellt, die im zuvor beschriebenen Verfahren erstellt wurden. Der Ereignishandler wird als statische Methode der Seite implementiert.
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; }
Verwenden einer dynamischen Vorlage
Wenn Ihnen eine dynamische Vorlage zur Verfügung steht, können Sie diese programmgesteuert instanziieren.
So verwenden Sie eine dynamische Vorlage
Erstellen Sie eine Instanz der dynamischen Vorlage, und übergeben Sie ihr einen entsprechenden Wert für den Elementtyp.
Weisen Sie die Instanz einer der Vorlageneigenschaften des auf Vorlagen basierenden Steuerelements zu, wie z. B. den Eigenschaften ItemTemplate, AlternatingItemTemplate oder HeaderTemplate.
Das folgende Codebeispiel zeigt, wie Sie die dynamische Vorlage mit einem Repeater-Steuerelement verwenden. In diesem Beispiel werden die Vorlagen instanziiert, während die Seite geladen wird und bevor das Steuerelement an seine Datenquelle gebunden wird.
Im folgenden Beispiel wird davon ausgegangen, dass eine Verbindung mit der Northwind-Beispieldatenbank in Microsoft SQL Server 7.0 oder höher möglich ist. Es wird eine Liste von Datensätzen der Tabelle Kategorien zurückgegeben.
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(); }
Ausführen des vollständigen Beispiels
Nachdem Sie alle zuvor aufgeführten Komponenten erstellt haben, fügen Sie dem Seitenmarkup ein Repeater-Steuerelement mit dem Namen Repeater1 hinzu, und führen Sie die Seite aus. Der vollständige Code und das Markup für die Webseite (unter Verwendung des Einzeldatei-Codemodells) sind im Folgenden dargestellt.
<%@ 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>