Développement d'un contrôle dépendant basé sur un modèle
Une propriété d'un contrôle peut facilement être liée à un élément de données (ou expression) unique en utilisant la syntaxe de liaison de données ASP.NET. Cette section traite du scénario plus complexe consistant à développer un contrôle qui possède des propriétés basées sur un modèle et liées à une source de données correspondant à un type collection (System.Collections.ICollection ou System.Collections.IEnumerable). Les modèles permettent à un développeur de pages de personnaliser la présentation des données qui sont liées au contrôle. Les contrôles Repeater et DataList sont des exemples de contrôles dépendants basés sur un modèle.
Pour une vue d'ensemble de la liaison de données dans les pages ASP.NET, consultez le Démarrage rapide ASP.NET —> Web Forms ASP.NET —> Contrôles serveur de liaison de données. Pour des informations générales sur la création d'un contrôle basé sur un modèle, consultez Développement d'un contrôle basé sur un modèle.
Un contrôle dépendant basé sur un modèle possède une propriété de source de données de type ICollection ou IEnumerable et une ou plusieurs propriétés de type ITemplate. Le conteneur de l'une des propriétés de modèle définit une propriété (généralement nommée DataItem
) à laquelle les données doivent être liées. Le contrôle implémente sa logique de liaison de données dans la méthode Databind qu'il hérite de Control. Il substitue la méthode CreateChildControls pour recréer la hiérarchie des contrôles enfants au moment de la publication. Ces étapes sont expliquées de façon plus détaillée dans la description suivante.
Pour développer un contrôle dépendant basé sur un modèle
Définissez un contrôle qui implémente l'interface System.Web.UI.INamingContainer.
public class TemplatedList : WebControl, INamingContainer {...} [Visual Basic] Public Class TemplatedList Inherits WebControl Implements INamingContainer ... End Class
Définissez une propriété de type 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
Le conteneur logique du modèle (spécifié dans l'attribut TemplateContainerAttribute) doit avoir une propriété à laquelle les données doivent être liées. Par convention, cette propriété est nommée DataItem. Pour plus d'informations sur les conteneurs logiques des propriétés de modèle, consultez Développement d'un contrôle basé sur un modèle. L'exemple suivant définit un conteneur pour la propriété de modèle.
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
Substituez la méthode DataBind (héritée de Control) pour fournir une logique de liaison de données. Cette démarche doit reposer sur la procédure suivante :
- Appelez la méthode OnDataBinding de la classe de base pour solliciter les gestionnaires (attachés par la page) qui évaluent les expressions de liaison de données sur votre contrôle.
- Effacez le contenu de la collection Controls.
- Effacez le contenu du ViewState des contrôles enfants.
- Créez les contrôles enfants en utilisant la source de données.
- Indiquez à l'infrastructure de page ASP.NET de suivre le ViewState pour votre contrôle.
Le code ci-dessous exécute ces étapes.
CreateChildControlsHierarchy
est une méthode d'assistance pour la mise en œuvre effective du travail de création de contrôles enfants. Consultez l'étape 5 pour plus d'informations.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
Substituez CreateChildControls pour recréer les contrôles enfants dans un scénario de publication. Cela implique la suppression du contenu de la collection Controls et la création de la hiérarchie des contrôles en utilisant l'état d'affichage (ViewState) à la place de la source de données. Le travail effectif de création des contrôles enfants est masqué dans la méthode
CreateControlHierarchy
décrite à l'étape 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
Définissez une source de données qui a des éléments null et utilisez cette source de données à la place de la source de données réelle lorsque vous créez la hiérarchie des contrôles au moment de la publication. Les étapes 3 et 4 créent la hiérarchie des contrôles en utilisant la source de données et l'état d'affichage enregistré, respectivement. Une source de données fictive permet à un contrôle d'implémenter un chemin de code unique pour les éléments communs de ces deux étapes.
Remarque Cette étape (étape 5) décrit les détails d'implémentation utilisés par les contrôles ASP.NET dépendants dans le .NET Framework. La classe
DummyDataSource
et la méthodeCreateControlHierarchy
illustrées dans le fragment de code ci-dessous ne se trouvent pas dans le .NET Framework mais doivent être définies par un développeur de contrôles. Vous n'êtes pas tenu d'implémenter ces éléments ; cependant, il est recommandé d'adopter cette approche ou une technique similaire afin de fournir un chemin de code commun pour la création de la hiérarchie des contrôles.Le fragment de code suivant définit une source de données fictive.
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
La classe
DummyDataSource
peut être utilisée pour définir la méthodeCreateControlHierarchy
, de la façon suivante.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
La méthode
CreateItem
effectue le travail réel de création du modèle et de liaison de la propriétéDataItem
à la source de données. Le fragment de code ci-dessous montre comment la méthodeCreateItem
est implémentée dans Exemple de contrôle dépendant basé sur un modèle. Notez que la méthodeCreateItem
est un détail d'implémentation et n'est pas définie dans le .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
Pour obtenir un exemple de contrôle dépendant qui implémente les étapes décrites dans cette rubrique, consultez Exemple de contrôle dépendant basé sur un modèle.