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

更新 : 2007 年 11 月

この例では、複雑なプロパティ (プロパティの型がプロパティを含むクラス) を有効にし、IStateManager インターフェイスを実装して ASP.NET のビューステートに参加する方法を示します。単純なプロパティの状態は、「サーバー コントロールのプロパティの例」で説明されているように、コントロールの ViewState プロパティを使用して管理できます。ただし、コレクション プロパティまたはサブプロパティを含むプロパティの状態を管理するには、プロパティを読み取り専用プロパティとして実装し、通常、IStateManager をプロパティ型の一部として実装する必要があります。

この例で定義する StateManagedAuthor 型は、IStateManager を実装する方法を示します。StateManagedAuthor クラスは、それ自体が FirstName、LastName などのサブプロパティを持っている複合型です。「カスタム プロパティの状態管理の例」で説明されている BookNew コントロールの Author プロパティは StateManagedAuthor 型です。

StateManagedAuthor における IStateManager インターフェイスの実装については、この後の「コードの説明」で説明します。

StateManagedAuthor クラスのコード リスト

' StateManagedAuthor.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(StateManagedAuthorConverter)) _
    > _
    Public Class StateManagedAuthor
        Implements IStateManager
        Private isTrackingViewStateValue As Boolean
        Private viewStateValue As StateBag

        Public Sub New()
            Me.New(String.Empty, String.Empty, String.Empty)
        End Sub

        Public Sub New(ByVal first As String, ByVal last As String)
            Me.New(first, String.Empty, last)
        End Sub

        Public Sub New(ByVal first As String, ByVal middle As String, _
            ByVal last As String)
            FirstName = first
            MiddleName = middle
            LastName = last
        End Sub

        < _
        Category("Behavior"), _
        DefaultValue(""), _
        Description("First name of author"), _
        NotifyParentProperty(True) _
        > _
        Public Overridable Property FirstName() As String
            Get
                Dim s As String = CStr(ViewState("FirstName"))
                If s Is Nothing Then s = String.Empty
                Return s
            End Get
            Set(ByVal value As String)
                ViewState("FirstName") = value
            End Set
        End Property

        < _
        Category("Behavior"), _
        DefaultValue(""), _
        Description("Last name of author"), _
        NotifyParentProperty(True) _
        > _
        Public Overridable Property LastName() As String
            Get
                Dim s As String = CStr(ViewState("LastName"))
                If s Is Nothing Then s = String.Empty
                Return s
            End Get
            Set(ByVal value As String)
                ViewState("LastName") = value
            End Set
        End Property

        < _
        Category("Behavior"), _
        DefaultValue(""), _
        Description("Middle name of author"), _
        NotifyParentProperty(True) _
        > _
        Public Overridable Property MiddleName() As String
            Get
                Dim s As String = CStr(ViewState("MiddleName"))
                If s Is Nothing Then s = String.Empty
                Return s
            End Get
            Set(ByVal value As String)
                ViewState("MiddleName") = value
            End Set
        End Property

        Protected Overridable ReadOnly Property ViewState() _
            As StateBag
            Get
                If viewStateValue Is Nothing Then
                    viewStateValue = New StateBag(False)

                    If isTrackingViewStateValue Then
                        CType(viewStateValue, _
                        IStateManager).TrackViewState()
                    End If
                End If
                Return viewStateValue
            End Get
        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

#Region "IStateManager implementation"
        Public ReadOnly Property IsTrackingViewState() As Boolean _
            Implements IStateManager.IsTrackingViewState
            Get
                Return isTrackingViewStateValue
            End Get
        End Property

        Public Sub LoadViewState(ByVal savedState As Object) _
            Implements IStateManager.LoadViewState
            If savedState IsNot Nothing Then
                CType(ViewState, _
                    IStateManager).LoadViewState(savedState)
            End If
        End Sub

        Public Function SaveViewState() As Object _
            Implements IStateManager.SaveViewState
            Dim savedState As Object = Nothing
            If viewStateValue IsNot Nothing Then
                savedState = CType(viewStateValue, _
                    IStateManager).SaveViewState
            End If
            Return savedState
        End Function

        Public Sub TrackViewState() _
            Implements IStateManager.TrackViewState
            isTrackingViewStateValue = True
            If viewStateValue IsNot Nothing Then
                CType(viewStateValue, IStateManager).TrackViewState()
            End If
        End Sub
#End Region

        Protected Sub SetDirty()
            viewStateValue.SetDirty(True)
        End Sub
    End Class
End Namespace
// StateManagedAuthor.cs
using System;
using System.Collections;
using System.ComponentModel;
using System.Globalization;
using System.Web.UI;

namespace Samples.AspNet.CS.Controls
{
    [
    TypeConverter(typeof(StateManagedAuthorConverter))
    ]
    public class StateManagedAuthor : IStateManager
    {
        private bool _isTrackingViewState;
        private StateBag _viewState;

        public StateManagedAuthor()
            :
            this(String.Empty, String.Empty, String.Empty)
        {
        }

        public StateManagedAuthor(string first, string last)
            :
            this(first, String.Empty, last)
        {
        }

        public StateManagedAuthor(string first, string middle, string last)
        {
            FirstName = first;
            MiddleName = middle;
            LastName = last;
        }

        [
        Category("Behavior"),
        DefaultValue(""),
        Description("First name of author"),
        NotifyParentProperty(true)
        ]
        public virtual String FirstName
        {
            get
            {
                string s = (string)ViewState["FirstName"];
                return (s == null) ? String.Empty : s;
            }
            set
            {
                ViewState["FirstName"] = value;
            }
        }

        [
        Category("Behavior"),
        DefaultValue(""),
        Description("Last name of author"),
        NotifyParentProperty(true)
        ]
        public virtual String LastName
        {
            get
            {
                string s = (string)ViewState["LastName"];
                return (s == null) ? String.Empty : s;
            }
            set
            {
                ViewState["LastName"] = value;
            }
        }

        [
        Category("Behavior"),
        DefaultValue(""),
        Description("Middle name of author"),
        NotifyParentProperty(true)
        ]
        public virtual String MiddleName
        {
            get
            {
                string s = (string)ViewState["MiddleName"];
                return (s == null) ? String.Empty : s;
            }
            set
            {
                ViewState["MiddleName"] = value;
            }
        }

        protected virtual StateBag ViewState
        {
            get
            {
                if (_viewState == null)
                {
                    _viewState = new StateBag(false);

                    if (_isTrackingViewState)
                    {
                        ((IStateManager)_viewState).TrackViewState();
                    }
                }
                return _viewState;
            }
        }


        public override string ToString()
        {
            return ToString(CultureInfo.InvariantCulture);
        }

        public string ToString(CultureInfo culture)
        {
            return TypeDescriptor.GetConverter(
                GetType()).ConvertToString(null, culture, this);
        }

        #region IStateManager implementation
        bool IStateManager.IsTrackingViewState
        {
            get
            {
                return _isTrackingViewState;
            }
        }

        void IStateManager.LoadViewState(object savedState)
        {
            if (savedState != null)
            {
                ((IStateManager)ViewState).LoadViewState(savedState);
            }
        }

        object IStateManager.SaveViewState()
        {
            object savedState = null;

            if (_viewState != null)
            {
                savedState =
                   ((IStateManager)_viewState).SaveViewState();
            }
            return savedState;
        }

        void IStateManager.TrackViewState()
        {
            _isTrackingViewState = true;

            if (_viewState != null)
            {
                ((IStateManager)_viewState).TrackViewState();
            }
        }
        #endregion

        internal void SetDirty()
        {
            _viewState.SetDirty(true);
        }
    }
}

コードの説明

StateManagedAuthor クラスは、ASP.NET の複合型が一般的に使用する IStateManager インターフェイスを実装するパターンを示します。StateManagedAuthor は、StateBag 型のプライベート変数に格納される ViewState というプロパティおよび C# では viewState、Visual Basic では viewStateValue というプロパティを定義します。ViewState プロパティは、Control クラスの ViewState プロパティに似ています。コントロールが単純なプロパティを Control クラスの ViewState 辞書に格納するように、StateManagedAuthor はプロパティを ViewState 辞書に格納します。

IStateManager インターフェイスには、IsTrackingViewState というプロパティ、および TrackViewStateSaveViewState、および LoadViewState の 3 つのメソッドがあります。IStateManager インターフェイスのメンバと Control クラスの対応するメソッドのセマンティクスは同じです。

IsTrackingViewState プロパティには IStateManager を実装する型があり、これによって、この型を使用するコントロールの状態追跡を調整できます。StateManagedAuthor クラスは、プライベートの Boolean フィールド (C# では isTrackingViewState、Visual Basic では isTrackingViewStateValue) を使用してこのプロパティを格納します。TrackViewState を実装することにより、StateManagedAuthor は isTrackingViewState または isTrackingViewStateValue を true に設定します。ViewState プロパティに対応するプライベートの viewState フィールドまたは viewStateValue フィールドの IStateManager.TrackViewState メソッドも呼び出します。TrackViewState メソッドは、ViewState プロパティに格納されている項目への変更の追跡を開始します。つまり、ViewState に対して TrackViewState が呼び出された後に ViewState 辞書の項目が設定されると、その項目には自動的に変更済みのマークが付けられます。

SaveViewState メソッドの実装において、StateManagedAuthor はプライベートの viewState フィールドまたは viewStateValue フィールドの対応するメソッドのみを呼び出します。同様に、LoadViewState メソッドの実装において、StateManagedAuthor は ViewState プロパティの対応するメソッドのみを呼び出します。「サーバー コントロールのプロパティの例」に説明されているように、ViewState プロパティの StateBag 型は IStateManager を実装し、状態管理機能が組み込まれた辞書です。

コントロールに IStateManager を実装する型を使用する場合は、自身の状態を維持し、コントロールの TrackViewStateSaveViewState、および LoadViewState の各メソッドから状態管理メソッドを呼び出すためにその型に依存します。したがって、「カスタム プロパティの状態管理の例」に説明されている BookNew コントロールは、StateManagedAuthor の TrackViewStateSaveViewState、および LoadViewState の各メソッドをそれぞれの実装から呼び出します。

StateManagedAuthorConverter クラスのコード リスト

次のコードの StateManagedAuthorConverter は、TypeConverterAttribute 属性によって StateManagedAuthor に関連付けられている型コンバータです。StateManagedAuthorConverter クラスによって、「型コンバータの例」に説明されているように、String 型から StateManagedAuthor 型への変換、およびその逆の変換ができます。この例では、BookNew クラスの Render メソッドに作成者のフルネームを出力するために StateManagedAuthorConverter を使用します。

ms178652.alert_note(ja-jp,VS.90).gifメモ :

StateManagedAuthor 型は、状態管理に型コンバータを必要としません。StateManagedAuthorConverter は、文字列から値に変換するためのオプションのユーティリティ クラスです。カスタム型の型コンバータを実装する場合は、StateManagedAuthor のコードに示されているように、型コンバータを呼び出して文字列表現を返すようにその型の ToString メソッドをオーバーライドする必要があります。

' StateManagedAuthorConverter.vb
Imports System
Imports System.ComponentModel
Imports System.ComponentModel.Design.Serialization
Imports System.Globalization
Imports System.Reflection

Namespace Samples.AspNet.VB.Controls
    Public Class StateManagedAuthorConverter
        Inherits ExpandableObjectConverter

        Public Overrides Function CanConvertFrom( _
        ByVal context As ITypeDescriptorContext, _
        ByVal sourceType As Type) As Boolean
            If sourceType Is GetType(String) Then
                Return True
            End If
            Return MyBase.CanConvertFrom(context, sourceType)
        End Function

        Public Overrides Function CanConvertTo( _
        ByVal context As ITypeDescriptorContext, _
        ByVal destinationType As Type) As Boolean
            If destinationType Is GetType(String) Then
                Return True
            End If
            Return MyBase.CanConvertTo(context, destinationType)
        End Function


        Public Overrides Function ConvertFrom( _
            ByVal context As ITypeDescriptorContext, _
            ByVal culture As CultureInfo, ByVal value As Object) _
            As Object
            If value Is Nothing Then
                Return New StateManagedAuthor()
            End If

            If (TypeOf value Is String) Then
                Dim s As String = CStr(value)
                If s.Length = 0 Then
                    Return New StateManagedAuthor()
                End If

                Dim parts() As String = s.Split(" ".ToCharArray)

                If (parts.Length < 2) Or (parts.Length > 3) Then
                    Throw New ArgumentException( _
                        "Name must have 2 or 3 parts.", "value")
                End If

                If parts.Length = 2 Then
                    Return New StateManagedAuthor(parts(0), parts(1))
                End If

                If parts.Length = 3 Then
                    Return New StateManagedAuthor(parts(0), _
                        parts(1), parts(2))
                End If
            End If
            Return MyBase.ConvertFrom(context, culture, value)
        End Function

        Public Overrides Function ConvertTo( _
        ByVal context As ITypeDescriptorContext, _
        ByVal culture As CultureInfo, ByVal value As Object, _
        ByVal destinationType As Type) As Object
            If value IsNot Nothing Then
                If Not (TypeOf value Is StateManagedAuthor) Then
                    Throw New ArgumentException( _
                        "Name must have 2 or 3 parts.", "value")
                End If
            End If

            If destinationType Is GetType(String) Then
                If value Is Nothing Then
                    Return String.Empty
                End If

                Dim auth As StateManagedAuthor = _
                    CType(value, StateManagedAuthor)

                If auth.MiddleName <> String.Empty Then
                    Return String.Format("{0} {1} {2}", _
                    auth.FirstName, _
                    auth.MiddleName, _
                    auth.LastName)
                Else
                    Return String.Format("{0} {1}", _
                        auth.FirstName, _
                        auth.LastName)
                End If
            End If

            Return MyBase.ConvertTo(context, culture, value, _
                destinationType)
        End Function
    End Class
End Namespace
// StateManagedAuthorConverter.cs
using System;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;
using System.Globalization;
using System.Reflection;

namespace Samples.AspNet.CS.Controls
{
    public class StateManagedAuthorConverter :
        ExpandableObjectConverter
    {
        public override bool CanConvertFrom(
            ITypeDescriptorContext context, Type sourceType)
        {
            if (sourceType == typeof(string))
            {
                return true;
            }
            return base.CanConvertFrom(context, sourceType);
        }

        public override bool CanConvertTo(
            ITypeDescriptorContext context, Type destinationType)
        {
            if (destinationType == typeof(string))
            {
                return true;
            }
            return base.CanConvertTo(context, destinationType);
        }

        public override object ConvertFrom( 
            ITypeDescriptorContext context,
            CultureInfo culture, object value)
        {
            if (value == null)
            {
                return new StateManagedAuthor();
            }

            if (value is string)
            {
                string s = (string)value;
                if (s.Length == 0)
                {
                    return new StateManagedAuthor();
                }

                string[] parts = s.Split(' ');

                if ((parts.Length < 2) || (parts.Length > 3))
                {
                    throw new ArgumentException(
                        "Name must have 2 or 3 parts.", "value");
                }

                if (parts.Length == 2)
                {
                    return new StateManagedAuthor(parts[0], parts[1]);
                }

                if (parts.Length == 3)
                {
                    return new StateManagedAuthor(parts[0], 
                         parts[1], parts[2]);
                }
            }

            return base.ConvertFrom(context, culture, value);
        }

        public override object ConvertTo(ITypeDescriptorContext context,
            CultureInfo culture, object value, Type destinationType)
        {
            if (value != null)
            {
                if (!(value is StateManagedAuthor))
                {
                    throw new ArgumentException(
                        "Name must have 2 or 3 parts.", "value");
                }
            }

            if (destinationType == typeof(string))
            {
                if (value == null)
                {
                    return String.Empty;
                }

                StateManagedAuthor auth = (StateManagedAuthor)value;

                if (auth.MiddleName != String.Empty)
                {
                    return String.Format("{0} {1} {2}",
                        auth.FirstName,
                        auth.MiddleName,
                        auth.LastName);
                }
                else
                {
                    return String.Format("{0} {1}",
                        auth.FirstName,
                        auth.LastName);
                }
            }

            return base.ConvertTo(context, culture,
                value, destinationType);
        }
    }
}

例のビルドと使用

このトピックの StateManagedAuthor クラスと StateManagedAuthorConverter クラスを「カスタム プロパティの状態管理の例」に記載されている BookNew コントロールおよび「サーバー コントロールのプロパティの例」に記載されている BookType 列挙と共にコンパイルします。

カスタム コントロールの例のコンパイルと使用の詳細については、「カスタム サーバー コントロールの例のビルド」を参照してください。

参照

概念

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

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

カスタム サーバー コントロールの例のビルド

その他の技術情報

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