Beispiel für ein vorlagenbasiertes Serversteuerelement
Aktualisiert: November 2007
Dieses Beispiel zeigt ein Steuerelement mit dem Namen VacationHome, das die Implementierung eines vorlagenbasierten Serversteuerelements veranschaulicht. Das VacationHome-Steuerelement definiert zwei verfügbar gemachte Eigenschaften: Title und Caption. Die Werte dieser Eigenschaften werden zur Entwurfszeit vom Seitenentwickler festgelegt und vom Steuerelement verwendet, um Eigenschaften für dessen untergeordnete Steuerelemente zu bestimmen. Durch Bearbeiten des <Template>-Elements im Steuerelement gibt der Seitenentwickler die Steuerelemente und das Markup zur Definition der Benutzeroberfläche des Steuerelements an. Des Weiteren ermöglicht das Steuerelement es dem Seitenentwickler, die <#% Container %>-Syntax zu verwenden, sodass zur Entwurfszeit auf Title- und Caption-Werte im Vorlagenmarkup verwiesen werden kann und diese in der wiedergegebenen Ausgabe angezeigt werden können. Die von einem Seitendesigner erstellte ASP.NET-Webseite könnte folgendermaßen aussehen:
<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>
Codeauflistung für das VacationHome-Steuerelement
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;
}
}
}
}
Codeerläuterung
Ein vorlagenbasiertes Steuerelement erweitert CompositeControl durch Hinzufügen einer Eigenschaft vom Typ ITemplate und durch Definieren eines Namenscontainers für das Steuerelement. Durch die Definition des Namenscontainers ermöglichen Sie dem Seitenentwickler, in der Vorlagendefinition die <#%Container%>-Syntax zu verwenden. Um die in der Vorlage definierten Steuerelemente zu hosten, definiert das Vorlagensteuerelement außerdem einen Eigenschaftentyp, der von Control abgeleitet wird. Bestimmte Attribute und Memberüberschreibungen werden implementiert, um das Verhalten von Vorlageneigenschaft, Hoststeuerelement und Namenscontainer zu koordinieren.
Die folgende Liste fasst die wesentlichen Implementierungsanforderungen für ein vorlagenbasiertes Steuerelement anhand des Beispiels von VacationHome zusammen. Eine genaue Erörterung der einzelnen Anforderungen erfolgt im Anschluss an diese Liste. Folgende Punkte werden am Beispiel des VacationHome-Steuerelements veranschaulicht:
Ableiten von der CompositeControl-Basisklasse. Ein vorlagenbasiertes Steuerelement stellt eine spezielle Form eines zusammengesetzten Steuerelements dar. Zwar können Sie auch von WebControl ableiten, jedoch hat CompositeControl den Vorteil der Implementierung von INamingContainer. Dadurch lässt sich die <#%Container%>-Syntax verwenden.
Implementieren einer Eigenschaft vom Typ ITemplate und Anwenden wichtiger Metadatenattribute auf diese Eigenschaft, um die Beibehaltung und den Namenscontainer dieser Eigenschaft zu definieren.
Verfügbarmachen einer Eigenschaft vom Typ Control oder einer von Control abgeleiteten Klasse, die dem Hosten der im Vorlagenelement definierten Steuerelemente dient. Dieses Steuerelement wird als Vorlagencontainer bezeichnet.
Überschreiben der CreateChildControls-Methode zum Instanziieren der Vorlagensteuerelemente in der Controls-Auflistung des Vorlagencontainers.
Definieren einer vom Steuerelement verwendeten Standardvorlage, wenn der Seitenentwickler keine Vorlage angibt (optional).
Definieren einer Designerklasse für das Steuerelement (optional). Mit der Designerklasse kann der Seitenentwickler die Vorlagen in einem visuellen Designer bearbeiten.
Die auf die ITemplate-Eigenschaft angewendeten Attribute sind BrowsableAttribute, PersistenceModeAttribute und TemplateContainerAttribute. Das TemplateContainerAttribute gibt den Typ des Steuerelements an, den der Seitenparser in einer Vorlage beim Auflösen der Container-Variable in einem Ausdruck wie <#%Container.Title%> verwenden soll. Der angegebene Typ muss INamingContainer implementieren und die Dateneigenschaften (in diesem Fall Caption und Title) für das Steuerelement definieren. Dieser Typ kann der Typ des Vorlagenbesitzers sein oder der Typ eines in der Steuerelementstruktur weiter oben stehenden Steuerelements. Im VacationHome-Steuerelement handelt es sich bei dem an den TemplateContainerAttribute-Konstruktor übergebenen Steuerelementtyp nicht um den Vorlagenbesitzer, sondern um das VacationHome-Steuerelement selbst. Das BrowsableAttribute wird auf false festgelegt, da Vorlagen im Eigenschaftenbearbeitungsfenster eines visuellen Designers in der Regel nicht bearbeitet werden. Das PersistenceModeAttribute wird auf InnerProperty festgelegt, da die Vorlagenspezifikation als inneres Element des Steuerelements geschrieben wird.
Das vorlagenbasierte Steuerelement muss eine Eigenschaft vom Typ Control definieren, die zum Container für die von der Vorlage erstellten Steuerelemente wird. Im Beispiel definiert das VacationHome-Steuerelement die Owner-Eigenschaft vom Typ TemplateOwner, welche wiederum von WebControl abgeleitet wird. Die TemplateOwner-Klasse ist als ToolboxItem(false) gekennzeichnet und zeigt damit an, dass die TemplateOwner-Klasse in einem visuellen Designer keine Toolbox-Unterstützung benötigt. Weitere Informationen finden Sie unter ToolboxItemAttribute. Die Steuerelemente in der Vorlage werden instanziiert und der Controls-Eigenschaft des Owner-Steuerelements hinzugefügt. Wenn das Steuerelement mehrere ITemplate-Eigenschaften verfügbar macht, können Sie für jede Vorlage eine eigene Vorlagencontainereigenschaft definieren. Die Owner-Eigenschaft wird als öffentliche Eigenschaft verfügbar gemacht. Dadurch kann der Seitendesigner die FindControl-Methode verwenden, um zur Laufzeit auf bestimmte Steuerelemente in der Vorlage zu verweisen.
Das VacationHome-Steuerelement überschreibt die CreateChildControls-Basismethode. Die CreateChildControls-Methode instanziiert die in der Template-Eigenschaft angegebenen Steuerelemente und fügt sie der Controls-Auflistung des Owner-Objekts hinzu. Der Controls-Auflistung der VacationHome -Instanz wird anschließend das Owner-Objekt hinzugefügt, und das Steuerelement kann dargestellt werden.
Wenn der Seitenentwickler keine Vorlage definiert hat, erstellt VacationHome eine Instanz von DefaultTemplate, die von ITemplate abgeleitet wird. Die InstantiateIn-Methode erstellt zwei Label-Steuerelemente, um die Title-Eigenschaft und die Caption-Eigenschaft anzuzeigen. Für das DataBinding-Ereignis jedes Steuerelements wird eine Ereignishandlermethode erstellt. Der DataBinding-Ereignishandler legt die Text-Eigenschaft auf die entsprechende Eigenschaft (Title oder Caption) von VacationHome fest.
Die VacationHomeDesigner-Klasse, die für die VacationHome-Klasse einen Designer implementiert, wird von ControlDesigner abgeleitet. Während der Initialisierung ermöglicht die mit TemplateEditing aufgerufene SetViewFlags-Methode das Bearbeiten einer Vorlage zur Entwurfszeit. Die GetDesignTimeHtml-Methode wird überschrieben, um das Steuerelement darzustellen, wenn es sich nicht im Vorlagenbearbeitungsmodus befindet. Im Code der überschriebenen TemplateGroups-Eigenschaft wird eine Vorlagengruppe definiert, die eine einzige Vorlage enthält. Jedes TemplateGroup-Objekt fügt der Benutzeroberfläche des visuellen Designers zur Vorlagenbearbeitung eine Vorlagenbearbeitungsoption hinzu. (In Visual Studio 2005 werden die Vorlagenbearbeitungsoptionen in einem dem Steuerelement zugeordneten Smarttag angezeigt.) Im VacationHome-Steuerelement ist "Item" die einzige Bearbeitungsauswahl. Jedes TemplateDefinition-Objekt erstellt eine Bearbeitungsvorlage für den Designer. Der templatePropertyName-Parameter des TemplateDefinition-Konstruktors gibt den Namen der Vorlageneigenschaft im Steuerelement an. Das DesignerAttribute wird auf die VacationHome-Klasse angewendet, um die Designerklasse anzugeben.
Testseite für das VacationHome-Steuerelement
Das folgende Beispiel zeigt eine ASPX-Seite, die das VacationHome-Steuerelement verwendet. Die erste Instanz des Steuerelements in der Seite gibt eine Vorlage für die ITemplate-Eigenschaft des Steuerelements an. Da für die zweite Instanz keine ITemplate-Eigenschaft angegeben wird, verwendet das VacationHome-Steuerelement zur Laufzeit die Standardvorlage.
<%@ 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>
Erstellen und Verwenden des Beispiels
Informationen zum Erstellen eines Steuerelements und über dessen Verwendung in einer Seite finden Sie unter Erstellen der Beispiele für benutzerdefinierte Serversteuerelemente. Für die Kompilierung müssen Sie einen Verweis auf die System.Design-Assembly hinzufügen.
Siehe auch
Konzepte
Beispiel für ein zusammengesetztes Steuerelement
Beispiel für typisierte Formate für untergeordnete Steuerelemente
Weitere Ressourcen
Entwickeln von benutzerdefinierten ASP.NET-Serversteuerelementen