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