カスタム プロパティの状態管理の例

更新 : 2007 年 11 月

この例では、型自体に状態管理が実装されるサーバー コントロールのプロパティを定義する方法を示します。この例の BookNew コントロールは Author プロパティを定義し、このプロパティの StateManagedAuthor 型が IStateManager インターフェイスを実装して自身の状態を管理します。StateManagedAuthor 型については、「カスタム型の状態管理の例」を参照してください。

このトピックの BookNew コントロールは、「サーバー コントロールのプロパティの例」で説明されている Book コントロールに似ています。このコントロールでは、サブプロパティを持つプロパティを定義する方法について説明されています。BookNew コントロールと Book コントロールの違いは、BookNew の Author プロパティが Author プロパティの状態管理をプロパティの StateManagedAuthor 型の状態管理メソッドに代行させることです。これとは異なり、Book コントロールは Author プロパティの状態を明示的に管理します。

状態管理を実装するメソッド (TrackViewStateSaveViewState、および LoadViewState) については、この後の「コードの説明」を参照してください。

BookNew コントロールのコード リスト

BookNew コントロールのコード リストを次に示します。状態管理は、BookNew の Author プロパティおよび StateManagedAuthor クラスの状態管理メソッド (TrackViewState、SaveViewState、および LoadViewState) によって実行されます。

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}:BookNew runat=""server""> </{0}:BookNew>") _
    > _
    Public Class BookNew
        Inherits WebControl
        Private authorValue As StateManagedAuthor

        < _
        Bindable(True), _
        Category("Appearance"), _
        DefaultValue(""), _
        Description("The name of the author."), _
        DesignerSerializationVisibility( _
            DesignerSerializationVisibility.Content), _
        PersistenceMode(PersistenceMode.InnerProperty) _
        > _
        Public Overridable ReadOnly Property Author() _
            As StateManagedAuthor
            Get
                If authorValue Is Nothing Then
                    authorValue = New StateManagedAuthor
                    If IsTrackingViewState Then
                        CType(authorValue, IStateManager).TrackViewState()
                    End If
                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 Render(ByVal writer As HtmlTextWriter)
            MyBase.AddAttributesToRender(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("&nbsp")
            writer.Write(String.Format("{0:F2}", Price))
            writer.RenderEndTag()
            writer.RenderEndTag()

            writer.RenderEndTag()
        End Sub

#Region "state management"
        Protected Overrides Sub LoadViewState( _
            ByVal savedState As Object)
            Dim p As Pair = TryCast(savedState, Pair)
            If p IsNot Nothing Then
                MyBase.LoadViewState(p.First)
                CType(Author, IStateManager).LoadViewState(p.Second)
                Return
            End If
            MyBase.LoadViewState(savedState)
        End Sub

        Protected Overrides Function SaveViewState() As Object
            Dim baseState As Object = MyBase.SaveViewState
            Dim thisState As Object = Nothing

            If authorValue IsNot Nothing Then
                thisState = _
                    CType(authorValue, IStateManager).SaveViewState()
            End If

            If thisState IsNot Nothing Then
                Return New Pair(baseState, thisState)
            Else
                Return baseState
            End If
        End Function

        Protected Overrides Sub TrackViewState()
            If authorValue IsNot Nothing Then
                CType(Author, IStateManager).TrackViewState()
            End If
            MyBase.TrackViewState()
        End Sub
#End Region

    End Class
End Namespace
// BookNew.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}:BookNew runat=\"server\"> </{0}:BookNew>")
    ]
    public class BookNew : WebControl
    {
        private StateManagedAuthor authorValue;

        [
        Bindable(true),
        Category("Appearance"),
        DefaultValue(""),
        Description("The name of the author."),
        DesignerSerializationVisibility(
            DesignerSerializationVisibility.Content),
        PersistenceMode(PersistenceMode.InnerProperty)
        ]
        public virtual StateManagedAuthor Author
        {
            get
            {
                if (authorValue == null)
                {
                    authorValue = new StateManagedAuthor();

                    if (IsTrackingViewState)
                    {
                        ((IStateManager)authorValue).TrackViewState();
                    }
                }
                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 Render(HtmlTextWriter writer)
        {
            base.AddAttributesToRender(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("&nbsp;");
            writer.Write(String.Format("{0:F2}", Price));
            writer.RenderEndTag();
            writer.RenderEndTag();

            writer.RenderEndTag();
        }

        #region state management
        protected override void LoadViewState(object savedState)
        {
            Pair p = savedState as Pair;
            if (p != null)
            {
                base.LoadViewState(p.First);
                ((IStateManager)Author).LoadViewState(p.Second);
                return;
            }
            base.LoadViewState(savedState);
        }

        protected override object SaveViewState()
        {
            object baseState = base.SaveViewState();
            object thisState = null;

            if (authorValue != null)
            {
                thisState = ((IStateManager)authorValue).SaveViewState();
            }

            if (thisState != null)
            {
                return new Pair(baseState, thisState);
            }
            else
            {
                return baseState;
            }

        }

        protected override void TrackViewState()
        {
            if (authorValue != null)
            {
                ((IStateManager)authorValue).TrackViewState();
            }
            base.TrackViewState();
        }
        #endregion

    }
}

コードの説明

BookNew コントロールは、IStateManager インターフェイスを実装することによって、プロパティの型が自身の状態を管理するプロパティを実装するパターンを示します。このトピックの BookNew コントロールのコードを確認するときは、StateManagedAuthor 型および BookNew コントロールの Author プロパティの型のコードも一緒に確認することが有効です。StateManagedAuthor のコード リストは、「カスタム型の状態管理の例」にあります。

BookNew は Author プロパティを StateManagedAuthor 型のプライベート フィールドに格納された読み取り専用プロパティとして定義します。Author プロパティ アクセサで、プロパティに対応するプライベート フィールドが null (Visual Basic では Nothing) の場合、BookNew はプライベート フィールドに新しい StateManagedAuthor オブジェクトを割り当てます。BookNew が状態の追跡を開始している場合、BookNew は、新規作成された StateManagedAuthor オブジェクトの TrackViewState メソッドを呼び出してこのオブジェクトの追跡を開始します。追跡の詳細については、「サーバー コントロールのプロパティの例」を参照してください。

Author プロパティは、自身の状態管理メソッド (TrackViewStateSaveViewState、および LoadViewState) から StateManagedAuthor オブジェクトの IStateManager のメソッドを呼び出して状態管理に参加します。

オーバーライドされた TrackViewState メソッドで、BookNew は基本クラスの TrackViewState メソッドと Author プロパティに対応する StateManagedAuthor オブジェクトの TrackViewState メソッドを呼び出します。

オーバーライドされた SaveViewState メソッドで、BookNew は基本クラスの SaveViewState メソッドと Author プロパティに対応する StateManagedAuthor オブジェクトの SaveViewState メソッドを呼び出します。Author プロパティに保存する状態がある場合、BookNew コントロールの SaveViewState メソッドは、基本クラスの状態と Author プロパティの状態を含む Pair オブジェクトを返します。Author プロパティに保存する状態がない場合、このメソッドは基本クラスへの SaveViewState の呼び出しによって返される状態のみを返します。状態に影響を与える一連のカスタム プロパティに基づいて、SaveViewState から PairTriplet、または Array の各型のオブジェクトを返す必要があります。これによって、LoadViewState メソッドで保存されている状態の各部を簡単に取得できます。この場合、基本クラスの状態と Author の状態の 2 つの項目があるため、Pair クラスが使用されます。

オーバーライドされた LoadViewState メソッドで、BookNew は LoadViewState メソッドで実行した操作の逆を実行します。BookNew は基本クラスと Author プロパティに状態を読み込みます。ただし、Author プロパティに保存する状態がない場合、BookNew は基本クラスのみに状態を読み込みます。基本クラスは復元する状態がない場合に実行する他のロジックをこのメソッドに実装していることがあるため、保存された状態が null (Visual Basic では Nothing) の場合にも、必ず基本クラスの LoadViewState メソッドを呼び出す必要があります。

BookNew コントロールのテスト ページ

BookNew コントロールを使用する .aspx ページの例を次に示します。

<%@ 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 Button_Click(object sender, EventArgs e)
  {
    BookNew1.Author.FirstName = "Bob";
    BookNew1.Author.LastName = "Kelly";
    BookNew1.Title = "Contoso Stories";
    BookNew1.Price = 39.95M;
    Button1.Visible = false;
  }  
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
  <head id="Head1" runat="server">
    <title>
      BookNew test page
    </title>
  </head>
  <body>
    <form id="Form1" runat="server">
      <aspSample:BookNew ID="BookNew1" Runat="server" 
        BorderStyle="Solid" BorderWidth="1px" Title="Tailspin Stories"
        CurrencySymbol="$" BackColor="#FFE0C0" Font-Names="Tahoma" 
        Price="16" BookType="Fiction">
        <Author FirstName="Judy" LastName="Lew" />
      </aspSample:BookNew>
      <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="BookNewTest.aspx" 
        Runat="server">
        Reload Page</asp:HyperLink>
    </form>
  </body>
</html>

例のビルドと使用

カスタム型の状態管理の例」に説明されている StateManagedAuthor クラスと StateManagedAuthorConverter クラスを使用して、BookNew コントロールをコンパイルします。

コントロールをビルドしてページ内で使用する方法の詳細については、「カスタム サーバー コントロールの例のビルド」を参照してください。

参照

概念

カスタム型の状態管理の例

サーバー コントロールのプロパティの例

その他の技術情報

ASP.NET カスタム サーバー コントロールの開発