サーバー コントロールのプロパティの例
更新 : 2007 年 11 月
この例では、Book というコントロールを作成し、単純なプロパティおよびサブプロパティを含むプロパティを永続化する方法を示します。
単純なプロパティは、文字列型または容易に文字列にマップできる種類のプロパティです。単純なプロパティは、追加作業を必要とせずにコントロールの開始タグの属性として永続化されます。String 型のプロパティおよび Boolean、Int16、Int32、Enum などの .NET Framework クラス ライブラリのプリミティブ値型プロパティは単純なプロパティです。ポストバックの前後の状態を管理するために単純なプロパティを ViewState 辞書に格納するためのコードを追加できます。
プロパティ型がさらにプロパティを含むクラスになっているプロパティは複合型プロパティと呼ばれます。たとえば、WebControl の Font プロパティは、Bold や Name などのプロパティを含む FontInfo クラスです。Bold と Name は、WebControl の Font プロパティのサブプロパティです。ASP.NET ページ フレームワークは、ハイフネーションされた構文 (Font-Bold="true" など) を使用してコントロールの開始タグのサブプロパティを永続化できますが、サブプロパティはページのコントロールのタグ内で永続化した方が読みやすくなります (<font Bold="true"> など)。
ビジュアル デザイナがサブプロパティをコントロールの子として永続化できるようにするには、プロパティおよびその型にいくつかのデザイン時属性を適用する必要があります。既定の永続化は、コントロールのタグのハイフネーションされた属性です。さらに、サブプロパティを含むプロパティには、この後の「コードの説明」にあるように、ビューステートを使用するためにカスタムの状態管理も必要です。
この例で定義されている Book コントロールは、カタログの書籍に関する情報を表示する Web ページで使用できるコントロールです。Book コントロールには、次のプロパティが定義されます。
Author プロパティ : Author カスタム型のサブプロパティを含むプロパティ。Author 型には、Author のサブプロパティである FirstName、LastName などのプロパティがあります。
BookType プロパティ : BookType カスタム列挙型の単純なプロパティ。BookType 列挙には、Fiction、NonFiction などの値が含まれます。
CurrencySymbol プロパティ : 組み込みの String 型の単純なプロパティ。
Price プロパティ : 組み込みの Decimal 型の単純なプロパティ。
Title プロパティ : 組み込みの String 型の単純なプロパティ。
BookType、CurrencySymbol、Price、および Title の各プロパティはすべて単純なプロパティのため、ページの永続化に特別な属性は必要ありません。ページ フレームワークは、次の例のように、コントロールのタグの属性と同様に既定でこれらのプロパティを永続化します。
<aspSample:Book Title="Wingtip Toys Stories"
CurrencySymbol="$"
Price="16"
BookType="Fiction">
</aspSample:Book>
Author プロパティおよび Author クラスのプロパティには、次の例のように、コントロールのタグ内の永続化を実現するためにデザイン時の属性が必要です。
<aspSample:Book >
<Author FirstName="Judy" LastName="Lew" />
</aspSample:Book>
Book コントロールは単純なプロパティを ViewState 辞書に格納します。ただし、Book コントロールは、ポストバックの前後の Author プロパティの状態を管理するために、カスタムの状態管理機能を実装する必要があります。
Book コントロールの製品レベルの実装は、発行元、発行日などの書籍に関するその他のデータのプロパティも定義できます。さらに、Author プロパティは、コレクション プロパティで置き換えることもできます。コレクション プロパティの実装の詳細については、「Web コントロールのコレクション プロパティの例」を参照してください。
メモ : |
---|
ページの開発者は、ページまたは個々のコントロールのビューステートを無効にできます。内部の機能のためにポストバックの前後で重要な状態をコントロールが維持する必要がある場合は、ASP.NET 2.0 で定義されているコントロール状態機構を使用できます。コントロールの状態については、「コントロールの状態とビューステートの例」を参照してください。 |
Book コントロールのコード リスト
' Book.vb
Option Strict On
Imports System
Imports System.ComponentModel
Imports System.Security.Permissions
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Namespace Samples.AspNet.VB.Controls
< _
AspNetHostingPermission(SecurityAction.Demand, _
Level:=AspNetHostingPermissionLevel.Minimal), _
AspNetHostingPermission(SecurityAction.InheritanceDemand, _
Level:=AspNetHostingPermissionLevel.Minimal), _
DefaultProperty("Title"), _
ToolboxData("<{0}:Book runat=""server""> </{0}:Book>") _
> _
Public Class Book
Inherits WebControl
Private authorValue As Author
Private initialAuthorString As String
< _
Bindable(True), _
Category("Appearance"), _
DefaultValue(""), _
Description("The name of the author."), _
DesignerSerializationVisibility( _
DesignerSerializationVisibility.Content), _
PersistenceMode(PersistenceMode.InnerProperty) _
> _
Public Overridable ReadOnly Property Author() As Author
Get
If (authorValue Is Nothing) Then
authorValue = New Author()
End If
Return authorValue
End Get
End Property
< _
Bindable(True), _
Category("Appearance"), _
DefaultValue(BookType.NotDefined), _
Description("Fiction or Not") _
> _
Public Overridable Property BookType() As BookType
Get
Dim t As Object = ViewState("BookType")
If t Is Nothing Then t = BookType.NotDefined
Return CType(t, BookType)
End Get
Set(ByVal value As BookType)
ViewState("BookType") = value
End Set
End Property
< _
Bindable(True), _
Category("Appearance"), _
DefaultValue(""), _
Description("The symbol for the currency."), _
Localizable(True) _
> _
Public Overridable Property CurrencySymbol() As String
Get
Dim s As String = CStr(ViewState("CurrencySymbol"))
If s Is Nothing Then s = String.Empty
Return s
End Get
Set(ByVal value As String)
ViewState("CurrencySymbol") = value
End Set
End Property
< _
Bindable(True), _
Category("Appearance"), _
DefaultValue("0.00"), _
Description("The price of the book."), _
Localizable(True) _
> _
Public Overridable Property Price() As Decimal
Get
Dim p As Object = ViewState("Price")
If p Is Nothing Then p = Decimal.Zero
Return CType(p, Decimal)
End Get
Set(ByVal value As Decimal)
ViewState("Price") = value
End Set
End Property
< _
Bindable(True), _
Category("Appearance"), _
DefaultValue(""), _
Description("The title of the book."), _
Localizable(True) _
> _
Public Overridable 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 RenderContents( _
ByVal writer As HtmlTextWriter)
writer.RenderBeginTag(HtmlTextWriterTag.Table)
writer.RenderBeginTag(HtmlTextWriterTag.Tr)
writer.RenderBeginTag(HtmlTextWriterTag.Td)
writer.WriteEncodedText(Title)
writer.RenderEndTag()
writer.RenderEndTag()
writer.RenderBeginTag(HtmlTextWriterTag.Tr)
writer.RenderBeginTag(HtmlTextWriterTag.Td)
writer.WriteEncodedText(Author.ToString())
writer.RenderEndTag()
writer.RenderEndTag()
writer.RenderBeginTag(HtmlTextWriterTag.Tr)
writer.RenderBeginTag(HtmlTextWriterTag.Td)
writer.WriteEncodedText(BookType.ToString())
writer.RenderEndTag()
writer.RenderEndTag()
writer.RenderBeginTag(HtmlTextWriterTag.Tr)
writer.RenderBeginTag(HtmlTextWriterTag.Td)
writer.Write(CurrencySymbol)
writer.Write(" ")
writer.Write(String.Format("{0:F2}", Price))
writer.RenderEndTag()
writer.RenderEndTag()
writer.RenderEndTag()
End Sub
Protected Overrides Sub LoadViewState( _
ByVal savedState As Object)
MyBase.LoadViewState(savedState)
Dim auth As Author = CType(ViewState("Author"), Author)
If auth IsNot Nothing Then
authorValue = auth
End If
End Sub
Protected Overrides Function SaveViewState() As Object
If authorValue IsNot Nothing Then
Dim currentAuthorString As String = _
authorValue.ToString()
If Not _
(currentAuthorString.Equals(initialAuthorString)) Then
ViewState("Author") = authorValue
End If
End If
Return MyBase.SaveViewState()
End Function
Protected Overrides Sub TrackViewState()
If authorValue IsNot Nothing Then
initialAuthorString = authorValue.ToString()
End If
MyBase.TrackViewState()
End Sub
End Class
End Namespace
// Book.cs
using System;
using System.ComponentModel;
using System.Security.Permissions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace Samples.AspNet.CS.Controls
{
[
AspNetHostingPermission(SecurityAction.Demand,
Level = AspNetHostingPermissionLevel.Minimal),
AspNetHostingPermission(SecurityAction.InheritanceDemand,
Level=AspNetHostingPermissionLevel.Minimal),
DefaultProperty("Title"),
ToolboxData("<{0}:Book runat=\"server\"> </{0}:Book>")
]
public class Book : WebControl
{
private Author authorValue;
private String initialAuthorString;
[
Bindable(true),
Category("Appearance"),
DefaultValue(""),
Description("The name of the author."),
DesignerSerializationVisibility(
DesignerSerializationVisibility.Content),
PersistenceMode(PersistenceMode.InnerProperty),
]
public virtual Author Author
{
get
{
if (authorValue == null)
{
authorValue = new Author();
}
return authorValue;
}
}
[
Bindable(true),
Category("Appearance"),
DefaultValue(BookType.NotDefined),
Description("Fiction or Not"),
]
public virtual BookType BookType
{
get
{
object t = ViewState["BookType"];
return (t == null) ? BookType.NotDefined : (BookType)t;
}
set
{
ViewState["BookType"] = value;
}
}
[
Bindable(true),
Category("Appearance"),
DefaultValue(""),
Description("The symbol for the currency."),
Localizable(true)
]
public virtual string CurrencySymbol
{
get
{
string s = (string)ViewState["CurrencySymbol"];
return (s == null) ? String.Empty : s;
}
set
{
ViewState["CurrencySymbol"] = value;
}
}
[
Bindable(true),
Category("Appearance"),
DefaultValue("0.00"),
Description("The price of the book."),
Localizable(true)
]
public virtual Decimal Price
{
get
{
object price = ViewState["Price"];
return (price == null) ? Decimal.Zero : (Decimal)price;
}
set
{
ViewState["Price"] = value;
}
}
[
Bindable(true),
Category("Appearance"),
DefaultValue(""),
Description("The title of the book."),
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 RenderContents(HtmlTextWriter writer)
{
writer.RenderBeginTag(HtmlTextWriterTag.Table);
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.WriteEncodedText(Title);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.WriteEncodedText(Author.ToString());
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.WriteEncodedText(BookType.ToString());
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.Write(CurrencySymbol);
writer.Write(" ");
writer.Write(String.Format("{0:F2}", Price));
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
}
protected override void LoadViewState(object savedState)
{
base.LoadViewState(savedState);
Author auth = (Author)ViewState["Author"];
if (auth != null)
{
authorValue = auth;
}
}
protected override object SaveViewState()
{
if (authorValue != null)
{
String currentAuthorString = authorValue.ToString();
if (!(currentAuthorString.Equals(initialAuthorString)))
{
ViewState["Author"] = authorValue;
}
}
return base.SaveViewState();
}
protected override void TrackViewState()
{
if (authorValue != null)
{
initialAuthorString = authorValue.ToString();
}
base.TrackViewState();
}
}
}
コードの説明
Book コントロールの Author プロパティに適用される DesignerSerializationVisibilityAttribute 属性と PersistenceModeAttribute 属性については、「Web コントロールのコレクション プロパティの例」を参照してください。これらの属性は、Author クラスのプロパティをシリアル化して永続化するために必要です。
ビューステート機構は、ASP.NET がポストバックの前後で状態を維持するために使用するテクニックです。この機構は、ページ処理の最後にページおよびそのコントロール ツリーの状態を文字列表現にシリアル化し、ポストバックの際にこの文字列を逆シリアル化します。既定では、ページは文字列を隠しフィールドとしてブラウザに送信します。詳細については、「ASP.NET の状態管理の概要」を参照してください。
単純なプロパティの状態を管理するために、これをコントロールの ViewState プロパティに格納される読み取り/書き込みプロパティとして定義します。Book コントロールは、単純なプロパティ (BookType、CurrencySymbol、Price、およびTitle) をこの方法で定義します。ViewState プロパティに格納するプロパティの状態は、追加作業なしに管理されます。
サブプロパティを含むプロパティを管理するには、読み取り専用のプロパティを定義し、オブジェクトの状態を管理するコードを記述します。そのためには、次のメソッドをオーバーライドします。
TrackViewState メソッド : 初期化後にプロパティの変更の追跡を開始するようにコントロールに指令します。
SaveViewState メソッド : ページの要求の最後にプロパティを保存します (変更されている場合)。
LoadViewState メソッド : 保存されている状態をポストバック時にプロパティに読み込みます。
メモ : ここで説明されているメソッド以外にも、複合型プロパティの状態を管理するメソッドはあります。チュートリアル : カスタム サーバー コントロールの開発と使用 で使用するメソッドは、各プロパティの変更に伴ってビューステートを変更することによって拡張できます。プロパティ クラスの状態は、「カスタム プロパティの状態管理の例」に示されている方法でも管理できます。
ViewState プロパティの型 (StateBag) は、状態管理機能が組み込まれた辞書です。StateBag クラスは、TrackViewState、SaveViewState、および LoadViewState メソッドを定義する IStateManager インターフェイスを実装します。StateBag クラスは、これらのメソッドを実装して、初期化後のコントロール プロパティの変更の追跡を開始し、ページ要求の最後に、変更されている項目を保存し、ポストバック時に状態を項目に保存します。StateBag は、ページ要求に対して OnInit メソッドが実行された後に項目が設定された場合、項目を変更済みとして指定することにより、項目の追跡を行います。たとえば、ページの初期化後に実行されるコードによって Book コントロールの Title プロパティが設定されると、ViewState["Title"] が変更されます。その結果、ViewState の "Title" キーに保存されていた値に変更済みのマークが付けられます。詳細については、「ASP.NET ページのライフ サイクルの概要」を参照してください。
Book コントロールは Author プロパティを読み取り専用プロパティとして定義し、次のようにしてカスタム状態管理機能を実装します。
TrackViewState メソッドで、Book コントロールは初期状態の Author プロパティを文字列に保存し、基本クラスの TrackViewState メソッドを呼び出して状態追跡を開始します。
SaveViewState メソッドで、Book コントロールは Author プロパティが初期値から変更されているかどうかを判定します。プロパティが変更されている場合、Book は "Author" キーを使用して Author プロパティを ViewState 辞書に保存します。Book コントロールは、基本クラスの SaveViewState メソッドを呼び出します。状態追跡が有効になっているため、ViewState に保存されている Author オブジェクトに自動的に変更済みのマークが付けられ、基本クラスのビューステートの一部として保存されます。
LoadViewState で、Book コントロールは、まず基本クラスの LoadViewState メソッドを呼び出します。この呼び出しによって、ViewState 辞書が自動的に復元されます。Book コントロールは、ViewState 辞書の "Author" の下に項目が保存されているかどうかを判定します。保存されている場合、コントロールは Author プロパティにビューステート値を読み込みます。
次のコード リストに定義されている Author 型にはカスタムの型コンバータがあるため、Author のインスタンスをビューステートに格納できます。型コンバータは、Author のインスタンスを文字列に変換し、その逆の変換も行います。型コンバータを定義すると、ビジュアル デザイナで Author のサブプロパティを設定できます。カスタムの型コンバータについては、「型コンバータの例」を参照してください。ビューステートに格納できる型は、ASP.NET がビューステートのシリアル化に使用する LosFormatter クラスによって制限されます。最も効率的にシリアル化できる型は Boolean、Int16、Int32、Enum、Pair、Triplet、Array、ArrayList、Hashtable などの .NET Framework クラス ライブラリのプリミティブ値型、上記のいずれかのプリミティブ型を含む任意の型、および String です。さらに、ビューステートには Pair、Triplet、Array、ArrayList、Hashtable などの型コンバータが定義されているカスタム型も格納できます。コントロールのためのビューステートのシリアル化を定義するときは、コントロールのデータを以上のいずれかの型に変換する必要があります。ビューステートのシリアル化機構と互換性がない型をビューステートに格納してもコントロールは正常にコンパイルされますが、実行時にエラーが発生します。また、シリアル化可能な型 (ISerializable インターフェイスを実装する型、または SerializableAttribute でマークされている型) はビューステートに格納できますが、これらの型のシリアル化はプリミティブ型よりかなり低速になります。
シリアル化のためにコントロールが提供する状態オブジェクトはコントロールのビューステートです。コントロールの ViewState プロパティはコントロールのビューステートの一部であり、追加作業なしにビューステート機構に自動的に参加できる部分です。Control クラスは、SaveViewState メソッドと LoadViewState メソッドで ViewState 辞書の変更された項目を保存して読み込むためのロジックを実装します。ビューステートのその他の部分は、SaveViewState メソッドをオーバーライドしてコントロールおよびコントロールの基本クラスがビューステートに保存する追加オブジェクトです。SaveViewState メソッドと LoadViewState メソッドをオーバーライドするときは、基本クラスの対応するメソッドを呼び出す必要があります。
Author クラスのコード リスト
FirstName、LastName、および MiddleName の各プロパティに NotifyParentPropertyAttribute を適用し、属性のコンストラクタ引数を true に設定すると、ビジュアル デザイナはこれらのプロパティの変更を親プロパティ (Author インスタンス) に伝達してシリアル化します。
' Author.vb
Option Strict On
Imports System
Imports System.Collections
Imports System.ComponentModel
Imports System.Globalization
Imports System.Web.UI
Namespace Samples.AspNet.VB.Controls
< _
TypeConverter(GetType(AuthorConverter)) _
> _
Public Class Author
Dim firstNameValue As String
Dim lastNameValue As String
Dim middleNameValue As String
Public Sub New()
Me.New(String.Empty, String.Empty, String.Empty)
End Sub
Public Sub New(ByVal firstname As String, _
ByVal lastname As String)
Me.New(firstname, String.Empty, lastname)
End Sub
Public Sub New(ByVal firstname As String, _
ByVal middlename As String, ByVal lastname As String)
firstNameValue = firstname
middleNameValue = middlename
lastNameValue = lastname
End Sub
< _
Category("Behavior"), _
DefaultValue(""), _
Description("First name of author."), _
NotifyParentProperty(True) _
> _
Public Overridable Property FirstName() As String
Get
Return firstNameValue
End Get
Set(ByVal value As String)
firstNameValue = value
End Set
End Property
< _
Category("Behavior"), _
DefaultValue(""), _
Description("Last name of author."), _
NotifyParentProperty(True) _
> _
Public Overridable Property LastName() As String
Get
Return lastNameValue
End Get
Set(ByVal value As String)
lastNameValue = value
End Set
End Property
< _
Category("Behavior"), _
DefaultValue(""), _
Description("Middle name of author."), _
NotifyParentProperty(True) _
> _
Public Overridable Property MiddleName() As String
Get
Return middleNameValue
End Get
Set(ByVal value As String)
middleNameValue = value
End Set
End Property
Public Overrides Function ToString() As String
Return ToString(CultureInfo.InvariantCulture)
End Function
Public Overloads Function ToString( _
ByVal culture As CultureInfo) As String
Return TypeDescriptor.GetConverter( _
Me.GetType()).ConvertToString(Nothing, culture, Me)
End Function
End Class
End Namespace
// Author.cs
using System;
using System.Collections;
using System.ComponentModel;
using System.Globalization;
using System.Web.UI;
namespace Samples.AspNet.CS.Controls
{
[
TypeConverter(typeof(AuthorConverter))
]
public class Author
{
private string firstnameValue;
private string lastnameValue;
private string middlenameValue;
public Author()
:
this(String.Empty, String.Empty, String.Empty)
{
}
public Author(string firstname, string lastname)
:
this(firstname, String.Empty, lastname)
{
}
public Author(string firstname,
string middlename, string lastname)
{
firstnameValue = firstname;
middlenameValue = middlename;
lastnameValue = lastname;
}
[
Category("Behavior"),
DefaultValue(""),
Description("First name of author."),
NotifyParentProperty(true),
]
public virtual String FirstName
{
get
{
return firstnameValue;
}
set
{
firstnameValue = value;
}
}
[
Category("Behavior"),
DefaultValue(""),
Description("Last name of author."),
NotifyParentProperty(true)
]
public virtual String LastName
{
get
{
return lastnameValue;
}
set
{
lastnameValue = value;
}
}
[
Category("Behavior"),
DefaultValue(""),
Description("Middle name of author."),
NotifyParentProperty(true)
]
public virtual String MiddleName
{
get
{
return middlenameValue;
}
set
{
middlenameValue = value;
}
}
public override string ToString()
{
return ToString(CultureInfo.InvariantCulture);
}
public string ToString(CultureInfo culture)
{
return TypeDescriptor.GetConverter(
GetType()).ConvertToString(null, culture, this);
}
}
}
BookType 列挙のコード リスト
' BookType.vb
Option Strict On
Imports System
Namespace Samples.AspNet.VB.Controls
Public Enum BookType
NotDefined = 0
Fiction = 1
NonFiction = 2
End Enum
End Namespace
// BookType.cs
using System;
namespace Samples.AspNet.CS.Controls
{
public enum BookType
{
NotDefined = 0,
Fiction = 1,
NonFiction = 2
}
}
Book コントロールのテスト ページ
Book コントロールを使用する .aspx ページの例を次に示します。
<%@ Page Language="C#" Debug="true" Trace="true"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
void Button_Click(object sender, EventArgs e)
{
Book1.Author.FirstName = "Bob";
Book1.Author.LastName = "Kelly";
Book1.Title = "Contoso Stories";
Book1.Price = 39.95M;
Button1.Visible = false;
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>
Book test page
</title>
</head>
<body>
<form id="Form1" runat="server">
<aspSample:Book ID="Book1" Runat="server"
Title="Tailspin Toys Stories" CurrencySymbol="$"
BackColor="#FFE0C0" Font-Names="Tahoma"
Price="16" BookType="Fiction">
<Author FirstName="Judy" LastName="Lew" />
</aspSample:Book>
<br />
<asp:Button ID="Button1" OnClick="Button_Click"
Runat="server" Text="Change" />
<asp:Button ID="Button2" Runat="server" Text="Refresh" />
<br />
<br />
<asp:HyperLink ID="Hyperlink1" href="BookTest.aspx"
Runat="server">
Reload Page</asp:HyperLink>
</form>
</body>
</html>
例のビルドと使用
この例のクラスを「型コンバータの例」に記載されている AuthorConverter クラスと共にコンパイルします。
カスタム コントロールの例のコンパイルと使用については、「カスタム サーバー コントロールの例のビルド」を参照してください。