Partager via


Contrôle serveur basé sur des modèles, exemple

Mise à jour : novembre 2007

Cet exemple présente un contrôle nommé VacationHome qui montre comment implémenter un contrôle serveur basé sur des modèles. Le contrôle VacationHome définit deux propriétés exposées, Title et Caption. Le concepteur de pages définit les valeurs de ces propriétés au moment du design et le contrôle utilise ces valeurs de propriété au moment de l'exécution pour définir des propriétés pour ses contrôles enfants. En modifiant l'élément <Template> dans le contrôle, le développeur de pages spécifie les contrôles et le balisage qui définissent l'interface utilisateur du contrôle. Le contrôle permet également aux développeurs de pages d'utiliser la syntaxe <#% Container %> afin que les valeurs Title et Caption puissent être référencées dans le balisage de modèle au moment du design et affichées dans le flux de sortie à restituer. Un concepteur de pages peut créer une page Web ASP.NET ressemblant à ceci :

<aspSample:VacationHome ID="VacationHome1" 
  Title="Condo for Rent in Hawaii"  
  Caption="Ocean view starting from $200" 
  Runat="server" Width="230px" Height="129px">
  <Template>
    <table bgcolor="aqua" align="center" id="Table1" 
       style="width: 286px; height: 260px">
      <tr>
        <td style="width: 404px" align="center">
          <asp:Label ID="Label1" Runat="server"
            Text="<%#Container.Title%>" 
             Font-Names="Arial, Helvetica"></asp:Label>
        </td>
      </tr>
      <tr>
        <td style="width: 404px">
        <asp:Image ID="Image1" Runat="server" 
          ImageUrl="~/images/hawaii.jpg" />
        </td>
      </tr>
      <tr>
        <td style="width: 404px; height: 26px;" align="center">
          <asp:Label ID="Label2" Runat="server" 
            Text="<%#Container.Caption%>" 
            Font-Names="Arial, Helvetica">
          </asp:Label>
        </td>
      </tr>
    </table>
  </Template>
</aspSample:VacationHome>

Liste du code du contrôle VacationHome

Option Strict On
Imports System
Imports System.ComponentModel
Imports System.Drawing
Imports System.Security.Permissions
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.Design

Namespace Samples.AspNet.VB.Controls
    < _
    AspNetHostingPermission(SecurityAction.Demand, _
        Level:=AspNetHostingPermissionLevel.Minimal), _
    AspNetHostingPermission(SecurityAction.InheritanceDemand, _
        Level:=AspNetHostingPermissionLevel.Minimal), _
    Designer(GetType(VacationHomeDesigner)), _
    DefaultProperty("Title"), _
    ToolboxData( _
        "<{0}:VacationHome runat=""server""> </{0}:VacationHome>") _
    > _
    Public Class VacationHome
        Inherits CompositeControl
        Private _template As ITemplate
        Private _owner As TemplateOwner

        < _
        Bindable(True), _
        Category("Data"), _
        DefaultValue(""), _
        Description("Caption") _
        > _
        Public Overridable Property Caption() As String
            Get
                Dim s As String = CStr(ViewState("Caption"))
                If s Is Nothing Then s = String.Empty
                Return s
            End Get
            Set(ByVal value As String)
                ViewState("Caption") = value
            End Set
        End Property

        < _
        Browsable(False), _
        DesignerSerializationVisibility( _
            DesignerSerializationVisibility.Hidden) _
        > _
        Public ReadOnly Property Owner() As TemplateOwner
            Get
                Return _owner
            End Get
        End Property

        < _
        Browsable(False), _
        PersistenceMode(PersistenceMode.InnerProperty), _
    DefaultValue(GetType(ITemplate), ""), _
    Description("Control template"), _
        TemplateContainer(GetType(VacationHome)) _
        > _
        Public Overridable Property Template() As ITemplate
            Get
                Return _template
            End Get
            Set(ByVal value As ITemplate)
                _template = value
            End Set
        End Property

        < _
        Bindable(True), _
        Category("Data"), _
        DefaultValue(""), _
        Description("Title"), _
        Localizable(True) _
        > _
        Public Property Title() As String
            Get
                Dim s As String = CStr(ViewState("Title"))
                If s Is Nothing Then s = String.Empty
                Return s
            End Get
            Set(ByVal value As String)
                ViewState("Title") = value
            End Set
        End Property


        Protected Overrides Sub CreateChildControls()
            Controls.Clear()
            _owner = New TemplateOwner()

            Dim temp As ITemplate = _template
            If temp Is Nothing Then
                temp = New DefaultTemplate
            End If

            temp.InstantiateIn(_owner)
            Me.Controls.Add(_owner)
        End Sub

        Public Overrides Sub DataBind()
            CreateChildControls()
            ChildControlsCreated = True
            MyBase.DataBind()
        End Sub


    End Class

    <ToolboxItem(False)> _
    Public Class TemplateOwner
        Inherits WebControl
    End Class

#Region "DefaultTemplate"
    NotInheritable Class DefaultTemplate
        Implements ITemplate

        Sub InstantiateIn(ByVal owner As Control) _
            Implements ITemplate.InstantiateIn
            Dim title As New Label
            AddHandler title.DataBinding, AddressOf title_DataBinding
            Dim linebreak As New LiteralControl("<br/>")
            Dim caption As New Label
            AddHandler caption.DataBinding, _
                AddressOf caption_DataBinding
            owner.Controls.Add(title)
            owner.Controls.Add(linebreak)
            owner.Controls.Add(caption)
        End Sub

        Sub caption_DataBinding(ByVal sender As Object, _
            ByVal e As EventArgs)
            Dim source As Label = CType(sender, Label)
            Dim container As VacationHome = _
                CType(source.NamingContainer, VacationHome)
            source.Text = container.Caption
        End Sub


        Sub title_DataBinding(ByVal sender As Object, _
            ByVal e As EventArgs)
            Dim source As Label = CType(sender, Label)
            Dim container As VacationHome = _
                CType(source.NamingContainer, VacationHome)
            source.Text = container.Caption
        End Sub
    End Class
#End Region


    Public Class VacationHomeDesigner
        Inherits ControlDesigner

        Public Overrides Sub Initialize(ByVal Component As IComponent)
            MyBase.Initialize(Component)
            SetViewFlags(ViewFlags.TemplateEditing, True)
        End Sub

        Public Overloads Overrides Function GetDesignTimeHtml() As String
            Return "<span>This is design-time HTML</span>"
        End Function

        Public Overrides ReadOnly Property TemplateGroups() As TemplateGroupCollection
            Get
                Dim collection As New TemplateGroupCollection
                Dim group As TemplateGroup
                Dim template As TemplateDefinition
                Dim control As VacationHome

                control = CType(Component, VacationHome)
                group = New TemplateGroup("Item")
                template = New TemplateDefinition(Me, "Template", control, "Template", True)
                group.AddTemplateDefinition(template)
                collection.Add(group)
                Return collection
            End Get
        End Property
    End Class

End Namespace
// VacationHome.cs
using System;
using System.ComponentModel;
using System.Drawing;
using System.Security.Permissions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.Design;

namespace Samples.AspNet.CS.Controls
{
    [
    AspNetHostingPermission(SecurityAction.InheritanceDemand, 
        Level=AspNetHostingPermissionLevel.Minimal),
    AspNetHostingPermission(SecurityAction.Demand,
        Level = AspNetHostingPermissionLevel.Minimal),
    Designer(typeof(VacationHomeDesigner)),
    DefaultProperty("Title"),
    ToolboxData(
        "<{0}:VacationHome runat=\"server\"> </{0}:VacationHome>"),
    ]
    public class VacationHome : CompositeControl
    {
        private ITemplate templateValue;
        private TemplateOwner ownerValue;

        [
        Bindable(true),
        Category("Data"),
        DefaultValue(""),
        Description("Caption")
        ]
        public virtual string Caption
        {
            get
            {
                string s = (string)ViewState["Caption"];
                return (s == null) ? String.Empty : s;
            }
            set
            {
                ViewState["Caption"] = value;
            }
        }

        [
        Browsable(false),
        DesignerSerializationVisibility(
            DesignerSerializationVisibility.Hidden)
        ]
        public TemplateOwner Owner
        {
            get
            {
                return ownerValue;
            }
        }

        [
        Browsable(false),
        PersistenceMode(PersistenceMode.InnerProperty),
        DefaultValue(typeof(ITemplate), ""),
        Description("Control template"),
        TemplateContainer(typeof(VacationHome))
        ]
        public virtual ITemplate Template
        {
            get
            {
                return templateValue;
            }
            set
            {
                templateValue = value;
            }
        }

        [
        Bindable(true),
        Category("Data"),
        DefaultValue(""),
        Description("Title"),
        Localizable(true)
        ]
        public virtual string Title
        {
            get
            {
                string s = (string)ViewState["Title"];
                return (s == null) ? String.Empty : s;
            }
            set
            {
                ViewState["Title"] = value;
            }
        }

        protected override void CreateChildControls()
        {
            Controls.Clear();
            ownerValue = new TemplateOwner();

            ITemplate temp = templateValue;
            if (temp == null)
            {
                temp = new DefaultTemplate();
            }

            temp.InstantiateIn(ownerValue);
            this.Controls.Add(ownerValue);
        }

        public override void DataBind()
        {
            CreateChildControls();
            ChildControlsCreated = true;
            base.DataBind();
        }

    }

    [
    ToolboxItem(false)
    ]
    public class TemplateOwner : WebControl
    {
    }

    #region DefaultTemplate
    sealed class DefaultTemplate : ITemplate
    {
        void ITemplate.InstantiateIn(Control owner)
        {
            Label title = new Label();
            title.DataBinding += new EventHandler(title_DataBinding);

            LiteralControl linebreak = new LiteralControl("<br/>");

            Label caption = new Label();
            caption.DataBinding 
                += new EventHandler(caption_DataBinding);

            owner.Controls.Add(title);
            owner.Controls.Add(linebreak);
            owner.Controls.Add(caption);

        }

        void caption_DataBinding(object sender, EventArgs e)
        {
            Label source = (Label)sender;
            VacationHome container = 
                (VacationHome)(source.NamingContainer);
            source.Text = container.Caption;
        }

        void title_DataBinding(object sender, EventArgs e)
        {
            Label source = (Label)sender;
            VacationHome container = 
                (VacationHome)(source.NamingContainer);
            source.Text = container.Title;
        }
    }
    #endregion


   public class VacationHomeDesigner : ControlDesigner
   {

        public override void Initialize(IComponent Component)
        {
            base.Initialize(Component);
            SetViewFlags(ViewFlags.TemplateEditing, true);
        }

        public override string GetDesignTimeHtml()
        {
            return "<span>This is design-time HTML</span>";
        }

        public override TemplateGroupCollection TemplateGroups
        {
            get {
                TemplateGroupCollection collection = new TemplateGroupCollection();
                TemplateGroup group;
                TemplateDefinition template;
                VacationHome control;

                control = (VacationHome)Component;
                group = new TemplateGroup("Item");
                template = new TemplateDefinition(this, "Template", control, "Template", true);
                group.AddTemplateDefinition(template);
                collection.Add(group);
                return collection;
            }
        }
    }

}

Explication du code

Un contrôle basé sur des modèles étend CompositeControl en ajoutant une propriété de type ITemplate et en définissant le conteneur de dénomination (naming container) du contrôle. En définissant un conteneur de dénomination, vous permettez au développeur de pages d'utiliser la syntaxe <#%Container%> dans la définition du modèle. Le modèle de contrôle définit également une propriété d'un type dérivé de Control pour héberger les contrôles définis dans le modèle. Les substitutions d'attributs et de membres spécifiques sont implémentées pour coordonner le comportement de la propriété de modèle, du contrôle hôte et du conteneur de dénomination.

La liste suivante résume les principaux prérequis d'implémentation pour un contrôle basé sur un modèle, comme le montre VacationHome. Vous trouverez plus d'informations sur chacun des prérequis dans la description figurant à la suite de la liste. Le contrôle VacationHome montre comment :

  • Dériver à partir de la classe de base CompositeControl. Un contrôle basé sur un modèle est un contrôle composite d'un genre spécial. Vous pouvez aussi dériver à partir de WebControl, mais CompositeControl ajoute l'implémentation du INamingContainer, ce qui permet d'utiliser la syntaxe <#%Container%>.

  • Implémenter une propriété de type ITemplate et lui appliquer les attributs de métadonnées correspondants pour définir sa persistance et son conteneur de dénomination.

  • Exposer une propriété de type Control ou une classe dérivée de Control qui serve à héberger les contrôles définis dans l'élément du modèle. Ce contrôle est connu sous le nom du conteneur de modèle.

  • Substituer la méthode CreateChildControls pour instancier les modèles de contrôle dans la collection Controls du conteneur de modèle.

  • Facultativement, définir un modèle par défaut, utilisé par le contrôle quand le développeur de pages ne spécifie aucun modèle.

  • Facultativement, définir une classe de concepteur pour le contrôle. La classe de concepteur permet au développeur de pages de modifier les modèles dans un concepteur visuel.

Les attributs appliqués à la propriété ITemplate sont BrowsableAttribute, PersistenceModeAttribute et TemplateContainerAttribute. TemplateContainerAttribute spécifie le type du contrôle que l'analyseur de page doit utiliser lors de la résolution de la variable Container dans une expression telle que <#%Container.Title%> dans un modèle. Le type spécifié doit implémenter INamingContainer et définir les propriétés de données (en l'occurrence, Caption et Title) du contrôle. Ce type peut être celui du propriétaire du modèle ou celui d'un contrôle situé plus haut dans l'arborescence des contrôles. Dans le contrôle VacationHome, le contrôle dont le type est passé au constructeur TemplateContainerAttribute n'est pas le propriétaire de modèle, mais le contrôle VacationHome lui-même. BrowsableAttribute a la valeur false, parce qu'en général les modèles ne sont pas modifiés dans la fenêtre de modification de propriété d'un concepteur visuel. PersistenceModeAttribute a la valeur InnerProperty, car la spécification du modèle est écrite comme un élément interne du contrôle.

Le contrôle basé sur un modèle doit définir une propriété de type Control, qui devient le conteneur des contrôles créés par le modèle. Dans l'exemple, le contrôle VacationHome définit la propriété Owner, qui est de type TemplateOwner, lequel dérive lui-même de WebControl. La classe TemplateOwner est marquée avec ToolboxItem(false) pour indiquer que la classe TemplateOwner n'a pas besoin d'être prise en charge par la boîte à outils dans un concepteur visuel. Pour plus d'informations, consultez ToolboxItemAttribute. Les contrôles du modèle sont instanciés et ajoutés à la propriété Controls du contrôle Owner. Si votre contrôle expose plusieurs propriétés ITemplate, vous pouvez définir pour chaque modèle une propriété distincte de conteneur de modèle. La propriété Owner est exposée comme une propriété publique. Cela permet au concepteur de pages d'utiliser la méthode FindControl pour référencer des contrôles spécifiques dans le modèle au moment de l'exécution.

Le contrôle VacationHome substitue la méthode de base CreateChildControls. La méthode CreateChildControls instancie les contrôles spécifiés dans la propriété Template et les ajoute à la collection Controls de l'objet Owner. L'objet Owner est ensuite ajouté à la collection Controls de l'instance VacationHome et le contrôle peut alors être rendu.

Si le développeur de pages n'a pas défini de modèle, VacationHome crée une instance de DefaultTemplate qui dérive de ITemplate. La méthode InstantiateIn crée deux contrôles Label pour afficher les propriétés Title et Caption. Une méthode de gestionnaire d'événements est créée pour l'événement DataBinding de chaque contrôle. Le gestionnaire d'événements DataBinding donne à la propriété Text la valeur de la propriété appropriée (Title ou Caption) de VacationHome.

La classe VacationHomeDesigner qui implémente un concepteur pour la classe VacationHome dérive de ControlDesigner. Durant l'initialisation, la méthode SetViewFlags, appelée avec TemplateEditing, permet de modifier le modèle au moment du design. La méthode GetDesignTimeHtml est substituée pour rendre le contrôle quand celui-ci n'est pas en mode de modification de modèle. Le code de la propriété TemplateGroups substituée définit un groupe de modèles qui contient un seul modèle. Chaque objet TemplateGroup ajoute un choix de modification de modèle à l'interface utilisateur d'édition de modèle du concepteur visuel. (Dans Visual Studio 2005, les choix d'édition de modèle s'affichent dans une balise active associée au contrôle). Dans le contrôle VacationHome, le seul choix d'édition est "élément". Chaque objet TemplateDefinition crée un modèle à modifier dans le concepteur. Le paramètre templatePropertyName du constructeur TemplateDefinition spécifie le nom de la propriété de modèle dans le contrôle. DesignerAttribute est appliqué à la classe VacationHome pour spécifier la classe de concepteur.

Page de test du contrôle VacationHome

L'exemple suivant illustre une page .aspx qui utilise le contrôle VacationHome. La première instance du contrôle dans la page spécifie un modèle de la propriété ITemplate du contrôle. La deuxième instance ne spécifie pas la propriété ITemplate, ce qui force le contrôle VacationHome à utiliser son modèle par défaut au moment de l'exécution.

<%@ Page Language="VB"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script >
    Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
        If Not IsPostBack Then
            VacationHome1.DataBind()
            VacationHome2.DataBind()
        End If
    End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
  <head id="Head1" >
    <title>
      VacationHome Control Test Page
    </title>
  </head>
  <body>
    <form id="form1" >
    <aspSample:VacationHome ID="VacationHome1" 
      Title="Condo for Rent in Hawaii"  
      Caption="Ocean view starting $200" 
      Runat="server" Width="230px" Height="129px">
    <Template>
      <table id="TABLE1"  
        style="width: 286px; height: 260px; 
        background-color:Aqua; text-align:center">
         <tr>
          <td style="width: 404px" align="center">
            <asp:Label ID="Label1" Runat="server" 
              Text="<%#Container.Title%>" 
              Font-Names="Arial, Helvetica"></asp:Label>
          </td>
        </tr>
        <tr>
          <td style="width: 404px">
            <asp:Image ID="Image1" Runat="server" 
              ImageUrl="~/images/hawaii.jpg" 
              AlternateText="Hawaii home" />
          </td>
        </tr>
        <tr>
          <td style="width: 404px; height: 26px;" align="center">
            <asp:Label ID="Label2" Runat="server" 
              Text="<%#Container.Caption%>" 
              Font-Names="Arial, Helvetica">
            </asp:Label>
          </td>
        </tr>
      </table>
     </Template>
    </aspSample:VacationHome>  
    <br /> <br />
      <br />
    The VacationHome control rendered with its default template:
    <br /> <br />
    <aspSample:VacationHome ID="VacationHome2" 
      Title="Condo for Rent in Hawaii" 
      Caption="Ocean view starting $200" 
      Runat="server" BorderStyle="Solid" BackColor="#66ffff" 
      Height="30px" Width="238px" Font-Names="Arial, Helvetica" />
    </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 >
  void Page_Load(object sender, EventArgs e)
  {
    if (!IsPostBack)
    {
      VacationHome1.DataBind();
      VacationHome2.DataBind();
    }
  }

</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
  <head id="Head1" >
    <title>
      VacationHome Control Test Page
    </title>
  </head>
  <body>
    <form id="form1" >
    <aspSample:VacationHome ID="VacationHome1" 
      Title="Condo for Rent in Hawaii"  
      Caption="Ocean view starting $200" 
      Runat="server" Width="230px" Height="129px">
    <Template>
      <table id="TABLE1"  
        style="width: 286px; height: 260px; 
        background-color:Aqua; text-align:center">
        <tr>
          <td style="width: 404px" align="center">
            <asp:Label ID="Label1" Runat="server" 
              Text="<%#Container.Title%>" 
              Font-Names="Arial, Helvetica"></asp:Label>
          </td>
        </tr>
        <tr>
          <td style="width: 404px">
            <asp:Image ID="Image1" Runat="server" 
              ImageUrl="~/images/hawaii.jpg" 
              AlternateText="Hawaii home" />
          </td>
        </tr>
        <tr>
          <td style="width: 404px; height: 26px;" align="center">
            <asp:Label ID="Label2" Runat="server" 
              Text="<%#Container.Caption%>" 
              Font-Names="Arial, Helvetica">
            </asp:Label>
          </td>
        </tr>
      </table>
     </Template>
    </aspSample:VacationHome>  
    <br /> <br />
      <br />
    The VacationHome control rendered with its default template:
    <br /> <br />
    <aspSample:VacationHome ID="VacationHome2" 
      Title="Condo for Rent in Hawaii" 
      Caption="Ocean view starting $200" 
      Runat="server" BorderStyle="Solid" BackColor="#66ffff" 
      Height="30px" Width="238px" Font-Names="Arial, Helvetica" />
    </form>
  </body>
</html>

Génération et utilisation de l'exemple

Pour plus d'informations sur la génération du contrôle et son utilisation dans une page, consultez Exemples de création de contrôles serveur personnalisés. Vous devez ajouter une référence à l'assembly System.Design pour la compilation.

Voir aussi

Concepts

Contrôle Web composite, exemple

Styles typés pour contrôles enfants, exemple

Autres ressources

Développement de contrôles serveur ASP.NET personnalisés