Sviluppo di un controllo basato su template con associazione a dati
Associare la proprietà di un controllo a un elemento o un'espressione di dati con la sintassi di associazione dati di ASP.NET è molto semplice. In questa sezione viene descritto lo scenario più complesso di sviluppo di un controllo con proprietà basate su template e associate a un'origine dati che è un tipo di insieme (System.Collections.ICollection o System.Collections.IEnumerable). I modelli consentono allo sviluppatore della pagina di personalizzare la presentazione dei dati associati al controllo. I controlli Repeater e DataList sono esempi di controlli con associazione a dati e basati su template.
Per una descrizione generale dell'associazione dati in pagine di ASP.NET, vedere Guida rapida di ASP.NET —> Web Form ASP.NET —> Associazione dati di controlli server. Per informazioni di base sulla creazione di un controllo basato su template, vedere Sviluppo di un controllo basato su template.
Un controllo con associazione a dati e basato su template dispone di una proprietà di origine dati di tipo ICollection o IEnumerable e di una o più proprietà di tipo ITemplate. Il contenitore di una delle proprietà di modello consente di definire una proprietà (generalmente denominata DataItem
) a cui associare i dati. Il controllo implementa la logica di associazione a dati nel metodo Databind che eredita da Control. Il controllo esegue l'override del metodo CreateChildControls per ricreare la gerarchia dei controlli figlio in seguito al postback. I passaggi vengono illustrati più dettagliatamente nella descrizione che segue.
Per sviluppare un controllo con associazione a dati basato su template
Definire un controllo che implementi l'interfaccia di System.Web.UI.INamingContainer.
public class TemplatedList : WebControl, INamingContainer {...} [Visual Basic] Public Class TemplatedList Inherits WebControl Implements INamingContainer ... End Class
Definire una proprietà di tipo System.Web.UI.ITemplate.
[TemplateContainer(typeof(TemplatedListItem))] public virtual ITemplate ItemTemplate { get { return itemTemplate; } set { itemTemplate = value; } } [Visual Basic] <TemplateContainer(GetType(TemplatedListItem))> _ Public Overridable Property ItemTemplate() As ITemplate Get Return _itemTemplate End Get Set _itemTemplate = value End Set End Property
Il contenitore logico del modello, specificato nell'attributo TemplateContainerAttribute, deve disporre di una proprietà a cui associare i dati. Per convenzione, questa proprietà è denominata DataItem. Per maggiori dettagli sui contenitori logici per le proprietà di modello, vedere Sviluppo di un controllo basato su template. Nell'esempio seguente viene definito un contenitore per la proprietà di modello.
public class TemplatedListItem : TableRow, INamingContainer { private object dataItem; public virtual object DataItem { get { return dataItem; } set { dataItem = value; } } [Visual Basic] Public Class TemplatedListItem Inherits TableRow Implements INamingContainer Private _dataItem As Object Public Overridable Property DataItem() As Object Get Return _dataItem End Get Set _dataItem = value End Set End Property End Class
Eseguire l'override del metodo DataBind, ereditato da Control, per mettere a disposizione una logica di associazione a dati. I passaggi necessari sono i seguenti:
- Chiamare il metodo OnDataBinding della classe base per richiamare i gestori allegati alla pagina che consentono di valutare le espressioni di associazione dati nel controllo.
- Cancellare l'insieme Controls.
- Cancellare la proprietà ViewState dei controlli figlio.
- Creare i controlli figlio tramite l'origine dati.
- Segnalare al framework della pagina ASP.NET di tenere traccia della proprietà ViewState per il controllo.
Il codice che segue consente di eseguire questi passaggi.
CreateChildControlsHierarchy
è un metodo di supporto per eseguire l'effettiva operazione di creazione dei controlli figlio. Per ulteriori dettagli, vedere il passaggio 5.public override void DataBind() { // Controls with a data-source property perform their // custom data binding by overriding DataBind to // evaluate any data-binding expressions on the control // itself. base.OnDataBinding(EventArgs.Empty); // Reset the control's state. Controls.Clear(); ClearChildViewState(); // Create the control hierarchy using the data source. CreateControlHierarchy(true); ChildControlsCreated = true; TrackViewState(); } [Visual Basic] Public Overrides Sub DataBind() ' Controls with a data-source property perform their custom data ' binding by overriding DataBind. ' Evaluate any data-binding expressions on the control itself. MyBase.OnDataBinding(EventArgs.Empty) ' Reset the control state. Controls.Clear() ClearChildViewState() ' Create the control hierarchy using the data source. CreateControlHierarchy(True) ChildControlsCreated = True TrackViewState() End Sub
Eseguire l'override di CreateChildControls per ricreare i controlli figlio in uno scenario di postback. Questa operazione implica la cancellazione dell'insieme Controls e la creazione della gerarchia di controllo tramite lo stato di visualizzazione invece che tramite l'origine dati. L'effettiva attività di creazione dei controlli figlio è nascosta nel metodo
CreateControlHierarchy
descritto al passaggio 5.protected override void CreateChildControls() { Controls.Clear(); if (ViewState["ItemCount"] != null) { // Create the control hierarchy using the view state, // not the data source. CreateControlHierarchy(false); } } [Visual Basic] Protected Overrides Sub CreateChildControls() Controls.Clear() If Not (ViewState("ItemCount") Is Nothing) Then ' Create the control hierarchy using the view state, ' not the data source. CreateControlHierarchy(False) End If End Sub
Definire un'origine dati con elementi null e utilizzarla al posto della vera origine dati per la creazione della gerarchia di controlli durante il postback. I passaggi 3 e 4 consentono di creare la gerarchia di controlli tramite l'origine dati e lo stato di visualizzazione salvato, rispettivamente. Un'origine dati fittizia consente a un controllo di implementare un singolo percorso di codice per gli elementi comuni di questi due passaggi.
Nota Nel passaggio 5 vengono descritti i dettagli di implementazione utilizzati dai controlli ASP.NET con associazione a dati in .NET Framework. La classe
DummyDataSource
e il metodoCreateControlHierarchy
illustrati nel frammento seguente non si trovano in .NET Framework ma è necessario che siano definiti da uno sviluppatore di controlli. Non è necessario implementare questi elementi, tuttavia è consigliabile utilizzare questa tecnica o una simile, per indicare un percorso di codice comune per la creazione della gerarchia di controllo.Nel frammento di codice seguente viene definita un'origine dati fittizia.
internal sealed class DummyDataSource : ICollection { private int dataItemCount; public DummyDataSource(int dataItemCount) { this.dataItemCount = dataItemCount; } // Implement other methods of the ICollection interface. ... public IEnumerator GetEnumerator() { return new DummyDataSourceEnumerator(dataItemCount); } private class DummyDataSourceEnumerator : IEnumerator { private int count; private int index; public DummyDataSourceEnumerator(int count) { this.count = count; this.index = -1; } public object Current { get { return null; } } // Define other methods of the IEnumerator interface. } } [Visual Basic] NotInheritable Friend Class DummyDataSource Implements ICollection Private dataItemCount As Integer Public Sub New(dataItemCount As Integer) Me.dataItemCount = dataItemCount End Sub ' Implement other methods of the ICollection interface. ... Public Function GetEnumerator() As IEnumerator Implements ICollection.GetEnumerator Return New DummyDataSourceEnumerator(dataItemCount) End Function Private Class DummyDataSourceEnumerator Implements IEnumerator Private count As Integer Private index As Integer Public Sub New(count As Integer) Me.count = count Me.index = - 1 End Sub Public ReadOnly Property Current() As Object Implements IEnumerator.Current Get Return Nothing End Get End Property ' Define other methods of the IEnumerator interface. ... End Class End Class
È possibile utilizzare
DummyDataSource
per definire il metodoCreateControlHierarchy
, come illustrato di seguito.private void CreateControlHierarchy(bool useDataSource) { IEnumerable dataSource = null; int count = -1; if (useDataSource == false) { // ViewState must have a non-null value for ItemCount because this is checked // by CreateChildControls. count = (int)ViewState["ItemCount"]; if (count != -1) { dataSource = new DummyDataSource(count); } } else { dataSource = this.dataSource; } if (dataSource != null) { int index = 0; count = 0; foreach (object dataItem in dataSource) { ... // Invoke a private helper method to create each item. CreateItem(...); count++; index++; } } if (useDataSource) { // Save the number of items contained for use in round trips. ViewState["ItemCount"] = ((dataSource != null) ? count : -1); } } [Visual Basic] Private Sub CreateControlHierarchy(useDataSource As Boolean) Dim dataSource As IEnumerable = Nothing Dim count As Integer = - 1 If useDataSource = False Then ' ViewState must have a non-null value for ItemCount because this is checked ' by CreateChildControls. count = CInt(ViewState("ItemCount")) If count <> - 1 Then dataSource = New DummyDataSource(count) End If Else dataSource = Me._dataSource End If If Not (dataSource Is Nothing) Then Dim table As New Table() Controls.Add(table) Dim selectedItemIndex As Integer = SelectedIndex Dim index As Integer = 0 count = 0 Dim dataItem As Object For Each dataItem In dataSource Dim itemType As ListItemType = ListItemType.Item If index = selectedItemIndex Then itemType = ListItemType.SelectedItem Else If index Mod 2 <> 0 Then itemType = ListItemType.AlternatingItem End If End If CreateItem(table, index, itemType, useDataSource, dataItem) count += 1 index += 1 Next dataItem End If If useDataSource Then ' Save the number of items contained for use in round trips. If Not (dataSource Is Nothing) Then ViewState("ItemCount") = count Else ViewState("ItemCount") = -1 End If End If End Sub
Il metodo
CreateItem
esegue l'effettiva attività di creazione del modello e di associazione della proprietàDataItem
all'origine dati. Nel frammento di codice seguente viene illustrato come viene implementato il metodoCreateItem
in Esempio di controllo basato su template con associazione a dati. Si noti che il metodoCreateItem
è un dettaglio di implementazione e non viene definito in .NET Framework.private TemplatedListItem CreateItem(Table table, int itemIndex, ListItemType itemType, bool dataBind, object dataItem) { TemplatedListItem item = new TemplatedListItem(itemIndex, itemType); TemplatedListItemEventArgs e = new TemplatedListItemEventArgs(item); if (itemTemplate != null) { itemTemplate.InstantiateIn(item.Cells[0]); } if (dataBind) { item.DataItem = dataItem; } OnItemCreated(e); table.Rows.Add(item); if (dataBind) { item.DataBind(); OnItemDataBound(e); item.DataItem = null; } return item; } [Visual Basic] Private Function CreateItem(table As Table, itemIndex As Integer, itemType As ListItemType, dataBind As Boolean, dataItem As Object) As TemplatedListItem Dim item As New TemplatedListItem(itemIndex, itemType) Dim e As New TemplatedListItemEventArgs(item) If Not (_itemTemplate Is Nothing) Then _itemTemplate.InstantiateIn(item.Cells(0)) End If If dataBind Then item.DataItem = dataItem End If OnItemCreated(e) table.Rows.Add(item) If dataBind Then item.DataBind() OnItemDataBound(e) item.DataItem = Nothing End If Return item End Function
Per un esempio di un controllo con associazione a dati che consente di implementare i passaggi descritti in questo argomento, vedere Esempio di controllo basato su template con associazione a dati.
Vedere anche
Esempio di controllo basato su template con associazione a dati