Procedura: creare dinamicamente modelli di controlli server Web ASP.NET
Aggiornamento: novembre 2007
Quando si utilizzano controlli basati su modelli, è possibile che non si saprà fino alla fase di esecuzione quali modelli sono necessari o quale testo o quali controlli il modello deve contenere. In tal caso, è possibile creare i modelli dinamicamente nel codice.
Nota: |
---|
È anche possibile creare modelli come controlli utente e associarli dinamicamente ai controlli presenti in una pagina. Per informazioni dettagliate, vedere Procedura: creare controlli utente ASP.NET basati su modelli. |
È possibile creare modelli nel codice per tutti i controlli che utilizzano modelli, ovvero i controlli DataList, Repeater, GridView, FormView, DetailsView e così via. Per il controllo GridView, i modelli vengono utilizzati per definire colonne anziché modelli di layout di riga, come avviene per gli altri due controlli.
Nota: |
---|
Esistono alcune differenze nella creazione di colonne modello per il controllo GridView rispetto ad altri controlli basati su modello. Per informazioni dettagliate, vedere Creazione di una colonna personalizzata in un controllo server Web GridView. |
Creazione della classe modello
Per creare modelli dinamici, occorre creare una classe modello di cui sia possibile creare un'istanza in seguito, quando necessario.
Per creare una classe modello
Creare una nuova classe che implementi l'interfaccia System.Web.UI.ITemplate.
È anche possibile passare al costruttore della classe un valore che la classe possa utilizzare per determinare che tipo di modello creare (ItemTemplate, AlternatingItemTemplate e così via).
Nota: Un modo indipendente dai tipi per passare il tipo di modello al costruttore consiste nell'aggiungere al costruttore un parametro di tipo ListItemType. L'enumerazione ListItemType definisce i tipi di modello possibili per Repeater, DataList e per altri controlli di elenco.
Nella classe implementare il metodo InstantiateIn che rappresenta il membro dell'interfaccia ITemplate.
Con tale metodo è possibile inserire un'istanza di testo e controlli nel contenitore specificato.
Nel metodo InstantiateIn creare i controlli per l'elemento modello, impostarne le proprietà e quindi aggiungerli all'insieme Controls del padre.
Per accedere al controllo padre, utilizzare il riferimento passato al metodo InstantiateIn.
Nota: Non è possibile aggiungere testo statico direttamente all'insieme Controls, ma è possibile creare controlli come il controllo Literal o il controllo LiteralControl, impostarne le proprietà Text e quindi aggiungerli all'insieme padre.
Per i controlli che richiedono l'associazione a dati, creare e associare un metodo per la gestione dell'evento del controllo DataBinding. L'evento viene generato dopo la creazione del modello e di tutti i relativi controlli e consente di recuperare i dati e utilizzarli in un controllo.
Nota: Non è possibile incorporare un'espressione di associazione dati come stringa durante la creazione dei controlli all'interno del modello, come avviene quando si definiscono modelli in fase di progettazione, poiché le espressioni di associazione dati vengono convertite in codice prima che il modello venga creato.
Nel gestore dell'evento DataBinding è possibile modificare il contenuto del controllo. Solitamente, ma non necessariamente, ciò avviene recuperando i dati dalla relativa origine e assegnandoli alla proprietà Text del controllo (o ad altra proprietà).
Nota: Per informazioni sull'associazione dati nelle pagine Web ASP.NET, vedere Accesso ai dati tramite ASP.NET.
Per aggiungere un'associazione dati a un modello dinamico, attenersi alla seguente procedura:
Aggiungere un gestore eventi di associazione dati ai controlli creati nel modello.
Creare il gestore a cui si sta effettuando l'associazione. Nel gestore recuperare i dati a cui si desidera effettuare l'associazione e assegnarli alla proprietà appropriata del controllo associato.
Nota: Se nei modelli sono inclusi più tipi di controlli, sarà necessario creare un gestore eventi di associazione dati per ogni tipo di controllo.
Nell'esempio di codice seguente viene illustrata una classe modello denominata MyTemplate che implementa l'interfaccia ITemplate. La classe MyTemplate definisce un costruttore che accetta un valore di enumerazione ListItemType per indicare il tipo di modello in fase di creazione. A seconda del tipo di modello, il codice crea tipi diversi di controlli e li aggiunge a un controllo PlaceHolder che viene quindi aggiunto all'insieme Controls del controllo padre. Per l'enumerazione ListItemType di Item e AlternatingItem viene creato un gestore eventi denominato Item_DataBinding.
La pagina Web risultante è una tabella HTML con un colore di sfondo diverso per il modello degli elementi alterni.
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); } }
Per creare il gestore dell'evento DataBinding
Creare un metodo che faccia parte della classe modello e che sia un peer degli altri metodi della classe (ad esempio InstantiateIn) o un metodo statico (Shared in Visual Basic) della pagina. Il nome del gestore deve corrispondere al nome utilizzato nella precedente associazione di evento.
Ottenere un riferimento all'oggetto DataItem contenente i dati effettuando le seguenti operazioni:
Ottenere uno riferimento all'elemento del modello attraverso la proprietà NamingContainer del controllo.
Utilizzare tale riferimento per ottenere la proprietà DataItem del contenitore di denominazione (dell'elemento modello).
Estrarre il singolo elemento dati dall'oggetto DataItem e utilizzarlo per impostare una proprietà del controllo da associare.
Nell'esempio di codice che segue viene mostrata una modalità di esecuzione dell'associazione dati all'interno di un modello dinamico. Viene illustrato un gestore eventi di associazione dati completo per i controlli PlaceHolder, Literal e Label creati nella procedura precedente. Il gestore eventi viene implementato come metodo statico della pagina.
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; }
Utilizzo del modello dinamico
Se si dispone di un modello dinamico, sarà possibile crearne un'istanza nel codice.
Per utilizzare un modello dinamico
Creare un'istanza del modello dinamico e passarvi, ove necessario, un valore che rappresenti un tipo di elemento.
Assegnare l'istanza a una delle proprietà modello del controllo basato su modelli, come la proprietà ItemTemplate, AlternatingItemTemplate o HeaderTemplate.
Nel codice di esempio che segue viene mostrato come utilizzare il modello dinamico con un controllo Repeater. In questo esempio, le istanze dei modelli vengono create durante il caricamento della pagina e prima che il controllo sia associato alla relativa origine dati.
Nell'esempio seguente si presuppone che ci si possa connettere al database di esempio Northwind in Microsoft SQL Server 7.0 o versioni successive. Restituisce un elenco di record dalla tabella 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(); }
Esecuzione dell'esempio completo
Dopo aver creato tutti i componenti elencati in precedenza, aggiungere un controllo Repeater denominato Repeater1 al codice della pagina e quindi eseguire la pagina. Il codice completo e il codice della pagina Web (utilizzando il modello di codice a file singolo) sono illustrati di seguito.
<%@ 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>