Partager via


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

  1. 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
    
  2. 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
    
  3. 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 :

    1. 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.
    2. Effacez le contenu de la collection Controls.
    3. Effacez le contenu du ViewState des contrôles enfants.
    4. Créez les contrôles enfants en utilisant la source de données.
    5. 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
    
  4. 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
    
  5. 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éthode CreateControlHierarchy 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éthode CreateControlHierarchy, 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éthode CreateItem est implémentée dans Exemple de contrôle dépendant basé sur un modèle. Notez que la méthode CreateItem 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.

Voir aussi

Exemple de contrôle dépendant basé sur un modèle