Comment : créer dynamiquement des modèles de contrôles serveur Web ASP.NET

Mise à jour : novembre 2007

Lorsque vous utilisez des contrôles basés sur des modèles, il se peut que vous ignoriez jusqu'à moment de l'exécution les modèles dont vous avez besoin, ou le texte ou les contrôles que le modèle doit contenir. Dans ce cas, vous pouvez créer les modèles dynamiquement dans le code.

Remarque :

Vous pouvez aussi créer des modèles comme les contrôles utilisateur et les lier dynamiquement aux contrôles de votre page. Pour plus d'informations, consultez Comment : créer des contrôles utilisateur ASP.NET avec modèles.

Vous pouvez créer des modèles dans le code pour tous les contrôles qui utilisent des modèles, parmi lesquels DataList, Repeater, GridView, FormView et DetailsView. Pour le contrôle GridView, vous utilisez des modèles pour définir les colonnes au lieu des modèles de disposition de lignes comme pour les autres contrôles.

Remarque :

Il existe quelques différences lorsque vous créez des colonnes de modèle pour le contrôle GridView par rapport à d'autres contrôles basés sur des modèles. Pour plus d'informations, consultez Création d'une colonne personnalisée dans un contrôle serveur Web GridView.

Création de la classe de modèle

Pour créer des modèles dynamiques, vous devez créer une classe de modèle que vous instanciez par la suite, lorsque cela est nécessaire.

Pour créer une classe de modèle

  1. Créez une classe qui implémente l'interface System.Web.UI.ITemplate.

  2. À titre facultatif, passez dans le constructeur de la classe une valeur que la classe peut utiliser pour déterminer le type de modèle à créer (ItemTemplate, AlternatingItemTemplate, etc.).

    Remarque :

    Une manière sécurisée de passer le type de modèle au constructeur consiste à ajouter un paramètre au constructeur avec le type ListItemType. L'énumération ListItemType définit les types de modèles possibles pour Repeater, DataList et d'autres contrôles de liste.

  3. Dans la classe, implémentez la méthode InstantiateIn, qui est membre de l'interface ITemplate.

    Cette méthode permet d'insérer une instance du texte et des contrôles dans le conteneur spécifié.

  4. Dans la méthode InstantiateIn, créez les contrôles pour l'élément de modèle, définissez leurs propriétés, puis ajoutez-les à la collection Controls du parent.

    Vous pouvez accéder au contrôle parent via la référence passée à la méthode InstantiateIn.

    Remarque :

    Vous ne pouvez pas ajouter directement un texte statique à la collection Controls, mais vous pouvez créer des contrôles comme le contrôle Literal ou le contrôle LiteralControl, définir leurs propriétés Text, puis ajouter ces contrôles à la collection parente.

  5. Pour les contrôles qui nécessitent une liaison de données, créez et liez une méthode pour gérer l'événement DataBinding du contrôle. Cet événement est déclenché une fois l'élément de modèle créé avec tous ses contrôles et vous permet d'extraire des données et de les utiliser dans un contrôle.

    Remarque :

    Vous ne pouvez pas incorporer une expression de liaison de données comme une chaîne lors de la création de contrôles dans le modèle, comme vous le faites lors de la définition de modèles au moment du design, parce que les expressions de liaison de données sont converties en code avant que votre modèle ne soit créé.

    Dans le gestionnaire de l'événement DataBinding, vous avez la possibilité de manipuler le contenu du contrôle. En général (mais pas nécessairement), vous extrayez les données d'un emplacement et les assignez à la propriété Text (ou à une autre propriété) du contrôle.

    Remarque :

    Pour plus d'informations sur la liaison de données dans les pages Web ASP.NET, consultez Accès aux données avec ASP.NET.

    Pour ajouter une liaison de données à un modèle dynamique, procédez comme suit :

    • Ajoutez un gestionnaire d'événements de liaison de données aux contrôles créés dans le modèle.

    • Créez le gestionnaire avec lequel vous souhaitez créer une liaison. Dans le gestionnaire, récupérez les données avec lesquelles vous souhaitez créer une liaison et assignez-les à la propriété adéquate du contrôle en cours de liaison.

      Remarque :

      Si vous avez plusieurs types de contrôles dans vos modèles, vous devez créer un gestionnaire d'événements de liaison de données différent pour chaque type de contrôle.

    L'exemple de code suivant illustre une classe de modèle nommée MyTemplate qui implémente l'interface ITemplate. La classe MyTemplate définit un constructeur qui accepte une valeur d'énumération ListItemType pour indiquer le type de modèle créé. Selon le type de modèle, le code crée des types différents de contrôles et les ajoute à un contrôle PlaceHolder qui est ensuite ajouté à la collection Controls du contrôle parent. Pour le ListItemType de Item et AlternatingItem, un gestionnaire d'événements nommé Item_DataBinding est créé.

    Le résultat de la page Web affichée est un tableau HTML avec une couleur d'arrière-plan distincte pour le modèle d'élément de remplacement.

    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);
        }
    }
    

Pour créer le gestionnaire pour l'événement DataBinding

  1. Créez une méthode qui fait partie de votre classe de modèle et est paire d'autres méthodes de la classe (comme InstantiateIn) ou d'une méthode statique (Shared en Visual Basic) de la page. Le nom du gestionnaire doit correspondre à celui que vous avez utilisé précédemment lors de la liaison de l'événement.

  2. Obtenez une référence à l'objet DataItem qui contient les données en procédant comme suit :

    1. Obtenez une référence à l'élément de modèle, accessible à partir de la propriété NamingContainer de votre contrôle.

    2. Utilisez cette référence pour obtenir la propriété DataItem du conteneur de dénomination (naming container) (élément du modèle).

    3. Extrayez l'élément de données individuel de l'objet DataItem et utilisez-le pour définir une propriété du contrôle que vous êtes en train de lier.

    L'exemple de code suivant illustre une façon d'exécuter la liaison de données dans un modèle dynamique. Il affiche un gestionnaire d'événements de liaison de données complet pour le contrôle PlaceHolder et pour les contrôles Literal et Label créés lors de la procédure antérieure. Le gestionnaire d'événements est implémenté comme une méthode statique de la page.

    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;
    }
    

Utilisation du modèle dynamique

Si vous disposez d'un modèle dynamique, vous pouvez l'instancier dans le code.

Pour utiliser un modèle dynamique

  1. Créez une instance de votre modèle dynamique, en lui passant une valeur de type d'élément, si besoin.

  2. Assignez l'instance à l'une des propriétés de modèle du contrôle basé sur des modèles, comme les propriétés ItemTemplate, AlternatingItemTemplate ou HeaderTemplate.

    L'exemple de code suivant montre comment utiliser le modèle dynamique avec un contrôle Repeater. Dans cet exemple, les modèles sont instanciés pendant le chargement de la page et avant que le contrôle ne soit lié à sa source de données.

    L'exemple suivant suppose que vous pouvez vous connecter à l'exemple de base de données Northwind sur Microsoft SQL Server 7.0 ou version ultérieure. Il retourne une liste d'enregistrements de la table Catégories.

    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();
    }
    

Exécution de l'exemple complet

Après avoir créé tous les composants répertoriés précédemment, ajoutez un contrôle Repeater nommé Repeater1 au balisage de la page et exécutez la page. Le code complet et le balisage pour la page Web (à l'aide du modèle de code à fichier unique) sont illustrés ci-dessous.

<%@ 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>

Voir aussi

Autres ressources

Utilisation des contrôles serveur Web ASP.NET