テンプレート サーバー コントロールの例
更新 : 2007 年 11 月
この例では、VacationHome というコントロールを使用してテンプレート サーバー コントロールを実装する方法を示します。VacationHome コントロールは、Title プロパティと Caption プロパティという 2 つの公開するプロパティを定義します。ページ デザイナはデザイン時にこれらプロパティの値を設定します。コントロールではそのプロパティ値を実行時に使用し、子コントロールのプロパティを設定します。コントロールの <Template> 要素を編集することによって、コントロールのユーザー インターフェイスを定義するコントロールとマークアップを指定できます。また、このコントロールによって、<#% Container %> 構文を使用できるようになるため、デザイン時にテンプレートのマークアップで Title 値と Caption 値を参照し、レンダリングされる出力に表示することができます。ページ デザイナは、次のような ASP.NET Web ページを作成できます。
<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"
runat="server" 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>
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;
}
}
}
}
コードの説明
テンプレート コントロールは、ITemplate 型のプロパティを追加し、コントロールの名前付けコンテナを定義することによって、CompositeControl を拡張できます。名前付けコンテナを定義すると、<#%Container%> の構文を使用してテンプレートを定義できるようになります。テンプレート コントロールは、テンプレートで定義されるコントロールをホストするために、Control から派生する型のプロパティも定義します。テンプレートのプロパティ、ホストのコントロール、および名前付けコンテナの動作を調整するために、特定の属性とメンバのオーバーライドが実装されます。
VacationHome のようなテンプレート コントロールの主な実装の要件を次の一覧にまとめます。各要件の詳細については、一覧の後で説明します。VacationHome コントロールの特徴は次のとおりです。
CompositeControl 基本クラスから派生します。テンプレート コントロールは、特別な種類の複合コントロールです。テンプレート コントロールは WebControl から派生させることもできますが、CompositeControl には、<#%Container%> の構文を使用するための INamingContainer の実装が追加されています。
ITemplate 型のプロパティを実装し、関連するメタデータの属性を適用して、永続性と名前付けコンテナを定義します。
テンプレート要素で定義されるコントロールをホストするために、Control 型のプロパティまたは Control から派生するクラスを公開します。このコントロールはテンプレート コンテナと呼ばれます。
CreateChildControls メソッドをオーバーライドして、テンプレート コンテナの Controls コレクションのテンプレート コントロールをインスタンス化します。
ページの開発者がテンプレートを指定しない場合にコントロールが使用する既定のテンプレートを定義します (省略可能)。
コントロールのデザイナ クラスを定義します (省略可能)。デザイナ クラスによって、テンプレートをビジュアル デザイナで編集できるようになります。
ITemplate プロパティに適用される属性は、BrowsableAttribute、PersistenceModeAttribute、および TemplateContainerAttribute の各属性です。TemplateContainerAttribute は、テンプレートの <#%Container.Title%> などの式の Container 変数を解決する際にページ パーサーが使用するコントロールの型を指定します。指定する型には INamingContainer を実装し、コントロールのデータのプロパティを定義する必要があります (この場合は Caption と Title)。この型は、テンプレートの所有者の型またはコントロール ツリーの上位のコントロールにすることもできます。VacationHome コントロールでは、TemplateContainerAttribute コンストラクタに型が渡されるコントロールはテンプレートの所有者ではなく、VacationHome コントロール自身です。テンプレートは通常、ビジュアル デザイナのプロパティ編集ウィンドウでは編集しないため、BrowsableAttribute は false に設定されます。テンプレートの仕様はコントロールの内部要素として記述されるため、PersistenceModeAttribute は InnerProperty に設定されます。
テンプレート コントロールは、テンプレートが作成するコントロールのコンテナになる Control 型のプロパティを定義する必要があります。この例の VacationHome コントロールは WebControl から派生する TemplateOwner 型の Owner プロパティを定義します。TemplateOwner クラスはビジュアル デザイナでツールボックスのサポートを必要としないため、TemplateOwner クラスには ToolboxItem(false) のマークが付けられます。詳細については、「ToolboxItemAttribute」を参照してください。テンプレートのコントロールはインスタンス化されて Owner コントロールの Controls プロパティに追加されます。コントロールが複数の ITemplate プロパティを公開する場合は、各テンプレートに対して個別のテンプレート コンテナのプロパティを定義することもできます。Owner プロパティはパブリック プロパティとして公開されます。これによって、ページ デザイナは FindControl メソッドを使用して実行時にテンプレートの特定のコントロールを参照できます。
VacationHome コントロールは、CreateChildControls 基本メソッドをオーバーライドします。CreateChildControls メソッドは、Template プロパティによって指定されるコントロールをインスタンス化し、Owner オブジェクトの Controls コレクションに追加します。Owner オブジェクトは VacationHome インスタンスの Controls コレクションに追加され、コントロールがレンダリングできるようになります。
ページの開発者がテンプレートを定義していない場合、VacationHome は ITemplate から派生する DefaultTemplate のインスタンスを作成します。InstantiateIn メソッドは、Title プロパティと Caption プロパティを表示するための 2 つの Label コントロールを作成します。各コントロールの DataBinding イベントのためにイベント ハンドラ メソッドが作成されます。DataBinding イベント ハンドラは VacationHome の適切なプロパティ (Title または Caption) に Text プロパティを設定します。
VacationHome クラスのデザイナを実装する VacationHomeDesigner クラスは、ControlDesigner から派生します。初期化中に、TemplateEditing と共に呼び出される SetViewFlags メソッドによって、デザイン時にテンプレートを編集できます。GetDesignTimeHtml メソッドは、テンプレート編集モードではない場合にコントロールをレンダリングするようにオーバーライドされます。オーバーライドされた TemplateGroups プロパティのコードは、単一のテンプレートを含むテンプレート グループを 1 つ定義します。各 TemplateGroup オブジェクトは、ビジュアル デザイナのテンプレート編集ユーザー インターフェイスにテンプレート編集の選択肢を追加します。Visual Studio 2005 のテンプレート編集の選択肢は、コントロールに関連付けられるスマート タグに表示されます。VacationHome コントロールの編集の選択肢は "Item" のみです。各 TemplateDefinition オブジェクトは、デザイナで編集するためのテンプレートを作成します。TemplateDefinition コンストラクタの templatePropertyName パラメータには、コントロールのテンプレート プロパティの名前を指定します。DesignerAttribute は、デザイナ クラスを指定するために VacationHome クラスに適用されます。
VacationHome コントロールのテスト ページ
VacationHome コントロールを使用する .aspx ページの例を次に示します。ページのコントロールの最初のインスタンスは、コントロールの ITemplate プロパティのテンプレートを指定します。2 番目のインスタンスは ITemplate プロパティを指定しないため、VacationHome コントロールは実行時に既定のテンプレートを使用します。
<%@ Page Language="VB"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
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" runat="server">
<title>
VacationHome Control Test Page
</title>
</head>
<body>
<form id="form1" runat="server">
<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" runat="server"
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 runat="server">
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" runat="server">
<title>
VacationHome Control Test Page
</title>
</head>
<body>
<form id="form1" runat="server">
<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" runat="server"
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>
例のビルドと使用
コントロールをビルドしてページ内で使用する方法については、「カスタム サーバー コントロールの例のビルド」を参照してください。コンパイルには System.Design アセンブリへの参照を追加する必要があります。