Condividi tramite


Esempio di controllo server basato su modelli

Aggiornamento: novembre 2007

In questo esempio, il controllo VacationHome illustra le modalità di implementazione di un controllo server basato su modelli. Il controllo VacationHome definisce due proprietà esposte: Title e Caption. Nella finestra di progettazione vengono impostati i valori di queste proprietà in fase di progettazione e tali valori verranno utilizzati dal controllo in fase di esecuzione per impostare le proprietà dei controlli figlio. Quando viene modificato l'elemento <Template> del controllo, lo sviluppatore della pagina specifica i controlli e il codice che definiscono l'interfaccia utente del controllo. Il controllo consente inoltre allo sviluppatore della pagina di utilizzare la sintassi <#% Container %> in modo che sia possibile fare riferimento ai valori Title e Caption nel codice del modello in fase di progettazione e che tali valori vengano visualizzati nell'output del rendering. Lo sviluppatore di una pagina può creare una pagina Web ASP.NET simile alla seguente:

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

Listato di codice per il controllo 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;
            }
        }
    }

}

Illustrazione del codice

Un controllo basato su modelli estende CompositeControl tramite l'aggiunta di una proprietà di tipo ITemplate e la definizione del contenitore di denominazione per il controllo. Definendo il contenitore di denominazione, si consente allo sviluppatore della pagina di utilizzare la sintassi <#%Container%> nella definizione del modello. Il controllo del modello definisce anche una proprietà di un tipo che deriva da Control per inserire i controlli definiti nel modello. Gli attributi specifici e gli override eseguiti dai membri vengono implementati per coordinare la proprietà del modello, il controllo host e il comportamento del contenitore di denominazione.

Nell'elenco riportato di seguito vengono riepilogati i principali requisti di implementazione per il controllo basato su modelli, come illustrato da VacationHome. Le informazioni dettagliate relative a ciascun requisito vengono fornite nella sezione che segue l'elenco. Il controllo VacationHome illustra quanto segue:

  • Derivazione dalla classe base CompositeControl. Un controllo basato su modelli è un tipo speciale di controllo composito. È anche possibile derivare da WebControl, ma CompositeControl aggiunge l'implementazione di INamingContainer, che consente di utilizzare la sintassi <#%Container%>.

  • Implementazione di una proprietà di tipo ITemplate e applicazione degli attributi di metadati rilevanti per la definizione della persistenza e del contenitore di denominazione.

  • Esposizione di una proprietà di tipo Control o di una classe derivata da Control che consente di contenere i controlli definiti nell'elemento del modello. Questo controllo viene anche detto contenitore del modello.

  • Esecuzione dell'override del metodo CreateChildControls per creare un'istanza dei controlli dei modelli nell'insieme Controls del contenitore dei modelli.

  • Facoltativamente, definizione di un modello predefinito utilizzato dal controllo quando lo sviluppatore di pagine non specifica alcun modello.

  • Facoltativamente, definizione della classe di progettazione del controllo. La classe di progettazione consente allo sviluppatore della pagina di modificare i modelli in una finestra di progettazione visiva.

Gli attributi applicati alla proprietà ITemplate sono BrowsableAttribute, PersistenceModeAttribute e TemplateContainerAttribute. TemplateContainerAttribute specifica il tipo di controllo che dovrebbe essere utilizzato dal parser della pagina per la soluzione della variabile Container in un'espressione quale <#%Container.Title%> in un modello. Il tipo specificato deve implementare INamingContainer e definire le proprietà dei dati, in questo caso di Caption e Title, per il controllo. Può essere il tipo del proprietario modello o di un controllo che si trova in una posizione più alta nella struttura ad albero dei controlli. Nel controllo VacationHome, il tipo che viene passato al costruttore TemplateContainerAttribute non è il proprietario del parametro, bensì il controllo VacationHome stesso. BrowsableAttribute è impostato su false, poiché in genere i modelli non vengono modificati in una finestra di modifica delle proprietà della finestra di progettazione visiva. PersistenceModeAttribute è impostato su InnerProperty, poiché la specifica del modello viene scritta come elemento interno del controllo.

Il controllo basato su modelli deve definire una proprietà di tipo Control che diventa il contenitore dei controlli creati dal modello. Nell'esempio, il controllo VacationHome definisce la proprietà Owner, di tipo TemplateOwner, che deriva da WebControl. La classe TemplateOwner viene contrassegnata da ToolboxItem(false) per indicare che la classe TemplateOwner non richiede il supporto della casella degli strumenti in una finestra di progettazione visiva. Per ulteriori informazioni, vedere ToolboxItemAttribute. Viene creata un'istanza dei controlli del modello che vengono aggiunti alla proprietà Controls del controllo Owner. Se il controllo espone più proprietà ITemplate, è possibile definire una proprietà del contenitore del modello separata per ogni modello. La proprietà Owner viene esposta come proprietà pubblica. Ciò consente allo sviluppatore della pagina di utilizzare il metodo FindControl per fare riferimento a controlli specifici del modello in fase di esecuzione.

Il controllo VacationHome esegue l'override del metodo CreateChildControls di base. Il metodo CreateChildControls crea un'istanza dei controlli specificati nella proprietà Template e li aggiunge all'insieme Controls dell'oggetto Owner. L'oggetto Owner viene quindi aggiunto all'insieme Controls dell'istanza VacationHome e risulta possibile eseguire il rendering del controllo.

Se lo sviluppatore della pagina non definisce un modello, VacationHome crea un'istanza di DefaultTemplate, che deriva da ITemplate. Il metodo InstantiateIn crea due controlli Label per la visualizzazione delle proprietà Title e Caption. Il metodo di gestione degli eventi viene creato per l'evento DataBinding di ogni controllo. Il gestore eventi DataBinding imposta la proprietà Text in base alla proprietà appropriata (Title o Caption) di VacationHome.

La classe VacationHomeDesigner implementata da uno sviluppatore per la classe VacationHome deriva da ControlDesigner. Durante l'inizializzazione, il metodo SetViewFlags, chiamato con TemplateEditing, consente di modificare il modello in fase di progettazione. Quando non viene utilizzata la modalità di modifica dei modelli, viene eseguito l'override del metodo GetDesignTimeHtml per il rendering del controllo. Il codice della proprietà sottoposta a override TemplateGroups definisce un gruppo di modelli contenente un modello. Ogni oggetto TemplateGroup aggiunge una scelta per la modifica dei modelli nell'interfaccia grafica di modifica del modello della pagina di progettazione visiva. In Visual Studio 2005, le scelte di modifica dei modelli vengono visualizzate in uno smart tag associato al controllo. Nel controllo VacationHome, l'unica scelta di modifica disponibile è "Item". Ogni oggetto TemplateDefinition crea un modello per l'esecuzione delle modifiche nella finestra di progettazione. Il parametro templatePropertyName del costruttore TemplateDefinition specifica il nome della proprietà del modello nel controllo. DesignerAttribute viene applicato alla classe VacationHome per specificare la classe di progettazione.

Pagina di prova per il controllo VacationHome

Il seguente esempio mostra una pagina ASPX che utilizza il controllo VacationHome. La prima istanza del controllo della pagina specifica un modello per la proprietà ITemplate del controllo. La seconda istanza non specifica la proprietà ITemplate, di conseguenza il controllo VacationHome utilizza il modello predefinito in fase di esecuzione.

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

Generazione e uso dell'esempio

Per informazioni sulla generazione del controllo e sul relativo uso in una pagina, vedere Generazione degli esempi dei controlli server personalizzati. È necessario aggiungere un riferimento all'assembly System.Design per la compilazione.

Vedere anche

Concetti

Esempio di controllo Web composito

Esempio di stili tipizzati per controlli figlio

Altre risorse

Sviluppo di controlli server ASP.NET personalizzati