Beispiel für die Zustandsverwaltung eines benutzerdefinierten Formats

Aktualisiert: November 2007

Das Beispiel zeigt, wie Sie eine komplexe Eigenschaft (eine Eigenschaft, deren Typ eine Klasse mit eigenen Eigenschaften ist) durch die Implementierung der IStateManager-Schnittstelle für die Teilnahme am ASP.NET-Ansichtszustand aktivieren. Wie in Beispiel für die Eigenschaften eines Serversteuerelements beschrieben, können Sie die ViewState-Eigenschaft eines Steuerelements verwenden, um den Zustand einfacher Eigenschaften zu verwalten. Um die Zustandsverwaltung jedoch für eine Auflistungseigenschaft oder eine Eigenschaft mit untergeordneten Eigenschaften verwenden zu können, müssen Sie die Eigenschaft als schreibgeschützte Eigenschaft und als Teil des normalerweise implementierten Eigenschaftentyps IStateManager implementieren.

Der in diesem Beispiel definierte StateManagedAuthor-Typ zeigt, wie Sie IStateManager implementieren. Die StateManagedAuthor-Klasse ist ein komplexer Typ und verfügt über eigene untergeordnete Eigenschaften wie FirstName und LastName. Ein Beispiel für den StateManagedAuthor-Typ ist die Author-Eigenschaft des BookNew-Steuerelements aus Beispiel für die Zustandsverwaltung einer benutzerdefinierten Eigenschaft.

Die Implementierung der IStateManager-Schnittstelle in StateManagedAuthor wird weiter unten im Abschnitt "Codeerläuterung" beschrieben.

Codeauflistung für die StateManagedAuthor-Klasse

' 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);
        }
    }
}

Codeerläuterung

Die StateManagedAuthor-Klasse zeigt die klassische Vorgehensweise beim Implementieren einer IStateManager-Schnittstelle, wie sie von komplexen Typen in ASP.NET häufig verwendet wird. StateManagedAuthor definiert eine Eigenschaft mit dem Namen ViewState, die in einer privaten Variable vom Typ StateBag gespeichert wird und den Namen viewState (C#) bzw. viewStateValue (Visual Basic) trägt. Die ViewState-Eigenschaft ahmt die ViewState-Eigenschaft der Control-Klasse nach. Die Eigenschaften von StateManagedAuthor werden im eigenen ViewState-Wörterbuch gespeichert, genauso wie die einfachen Eigenschaften eines Steuerelements im ViewState-Wörterbuch der Control-Klasse gespeichert werden.

Die IStateManager-Schnittstelle verfügt über eine IsTrackingViewState-Eigenschaft und drei Methoden: TrackViewState, SaveViewState und LoadViewState. Die Member der IStateManager-Schnittstelle weisen die gleiche Semantik wie die entsprechenden Methoden in der Control-Klasse auf.

Mit der IsTrackingViewState-Eigenschaft kann ein Typ, der IStateManager implementiert, sich mit der Zustandsverfolgung im Steuerelement abstimmen, in dem der Typ verwendet wird. Die StateManagedAuthor-Klasse verwendet ein privates Boolean-Feld (isTrackingViewState in C# und isTrackingViewStateValue in Visual Basic), um diese Eigenschaft zu speichern. Bei der Implementierung von TrackViewState legt die StateManagedAuthor-Klasse isTrackingViewState bzw. isTrackingViewStateValue auf true fest. Die Klasse ruft außerdem die IStateManager.TrackViewState-Methode des privaten viewState-Felds bzw. des privaten viewStateValue-Felds auf, das der ViewState-Eigenschaft entspricht. Die TrackViewState-Methode startet die Verfolgung von Änderungen an Elementen, die in der ViewState-Eigenschaft gespeichert sind. Wenn also ein Element aus dem ViewState-Wörterbuch festgelegt wird, nachdem TrackViewState für ViewState aufgerufen wurde, wird das Element automatisch als geändert gekennzeichnet.

Bei der Implementierung der SaveViewState-Methode wird von StateManagedAuthor nur die entsprechende Methode des privaten viewState-Felds bzw. des privaten viewStateValue-Felds aufgerufen. Gleichermaßen wird bei der Implementierung der LoadViewState-Methode von StateManagedAuthor nur die entsprechende Methode der ViewState-Eigenschaft aufgerufen. Wie in Beispiel für die Eigenschaften eines Serversteuerelements beschrieben, implementiert der StateBag-Typ der ViewState-Eigenschaft IStateManager und ein Wörterbuch mit integrierter Zustandsverwaltung.

Wenn Sie einen Typ verwenden, der IStateManager in einem Steuerelement implementiert, sind Sie darauf angewiesen, dass der Typ seinen Zustand selbst verwaltet und die Zustandsverwaltungsmethoden des Typs aus den Methoden TrackViewState, SaveViewState und LoadViewState des Steuerelements abruft. Deshalb ruft das in Beispiel für die Zustandsverwaltung einer benutzerdefinierten Eigenschaft beschriebene BookNew-Steuerelement die Methoden TrackViewState, SaveViewState und LoadViewState von StateManagedAuthor über die eigene Implementierung dieser Methoden auf.

Codeauflistung für die StateManagedAuthorConverter-Klasse

Beim StateManagedAuthorConverter der folgenden Codeauflistung handelt es sich um den Typkonverter, der StateManagedAuthor mithilfe des TypeConverterAttribute-Attributs zugeordnet ist. Mit der StateManagedAuthorConverter-Klasse können Sie einen String-Typ in einen StateManagedAuthor-Typ konvertieren und umgekehrt. Eine nähere Beschreibung finden Sie unter Beispiel für einen Typkonverter. Der StateManagedAuthorConverter wird in diesem Beispiel verwendet, um in der Render-Methode der BookNew-Klasse den vollständigen Namen des Autors auszugeben.

Hinweis:

Der StateManagedAuthor-Typ benötigt für die Zustandsverwaltung keinen Typkonverter. StateManagedAuthorConverter wird als optionale Dienstprogrammklasse für die Konvertierung von Zeichenfolgen in einen Wert bereitgestellt. Wenn Sie für einen benutzerdefinierten Typ einen Typkonverter implementieren, sollten Sie zum Aufrufen des Typkonverters und für das Zurückgeben einer Zeichenfolgendarstellung die ToString-Methode des Typs überschreiben. Siehe dazu die Codeauflistung für StateManagedAuthor.

' 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);
        }
    }
}

Erstellen und Verwenden des Beispiels

Kompilieren Sie die StateManagedAuthor-Klasse und die StateManagedAuthorConverter-Klasse, die in diesem Thema aufgeführt sind, mit dem in Beispiel für die Zustandsverwaltung einer benutzerdefinierten Eigenschaft aufgeführten BookNew-Steuerelement und mit der in Beispiel für die Eigenschaften eines Serversteuerelements aufgeführten BookType-Enumeration.

Weitere Informationen über das Kompilieren und Verwenden der benutzerdefinierten Beispielsteuerelemente finden Sie unter Erstellen der Beispiele für benutzerdefinierte Serversteuerelemente.

Siehe auch

Konzepte

Beispiel für die Zustandsverwaltung einer benutzerdefinierten Eigenschaft

Beispiel für die Eigenschaften eines Serversteuerelements

Erstellen der Beispiele für benutzerdefinierte Serversteuerelemente

Weitere Ressourcen

Entwickeln von benutzerdefinierten ASP.NET-Serversteuerelementen