Udostępnij za pośrednictwem


Custom Property State Management Example

This example shows how to define a server control property whose type implements its own state management. The BookNew control in the example defines an Author property whose type, StateManagedAuthor, performs its own state management by implementing the IStateManager interface. The StateManagedAuthor type is described in Custom Type State Management Example.

The BookNew control in this topic is similar to the Book control described in Server Control Properties Example, which shows how to define a property that has subproperties. The difference between the BookNew and Book controls is that the type of the Author property in BookNew delegates state management of the Author property to the state management methods of the property's StateManagedAuthor type. In contrast, the Book control explicitly manages the state of its Author property.

The methods used to implement state management (TrackViewState, SaveViewState, and LoadViewState) are described in the "Code Discussion" section later in this topic.

Code Listing for the BookNew Control

The following code listing of the BookNew control. State management is performed by the Author property of BookNew and the state management methods (TrackViewState, SaveViewState, and LoadViewState) of the StateManagedAuthor class.

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>") _
    > _
    PublicClass BookNew
        Inherits WebControl
        Private authorValue As StateManagedAuthor

        < _
        Bindable(True), _
        Category("Appearance"), _
        DefaultValue(""), _
        Description("The name of the author."), _
        DesignerSerializationVisibility( _
            DesignerSerializationVisibility.Content), _
        PersistenceMode(PersistenceMode.InnerProperty) _
        > _
        PublicOverridableReadOnlyProperty Author() _
            As StateManagedAuthor
            GetIf authorValue IsNothingThen
                    authorValue = New StateManagedAuthor
                    If IsTrackingViewState ThenCType(authorValue, IStateManager).TrackViewState()
                    EndIfEndIfReturn authorValue
            EndGetEndProperty

        < _
        Bindable(True), _
        Category("Appearance"), _
        DefaultValue(BookType.NotDefined), _
        Description("Fiction or Not") _
        > _
        PublicOverridableProperty BookType() As BookType
            GetDim t AsObject = ViewState("BookType")
                If t IsNothingThen t = BookType.NotDefined
                ReturnCType(t, BookType)
            EndGetSet(ByVal value As BookType)
                ViewState("BookType") = value
            EndSetEndProperty

        < _
        Bindable(True), _
        Category("Appearance"), _
        DefaultValue(""), _
        Description("The symbol for the currency."), _
        Localizable(True) _
        > _
        PublicOverridableProperty CurrencySymbol() AsStringGetDim s AsString = CStr(ViewState("CurrencySymbol"))
                If s IsNothingThen s = String.Empty
                Return s
            EndGetSet(ByVal value AsString)
                ViewState("CurrencySymbol") = value
            EndSetEndProperty

        < _
         Bindable(True), _
         Category("Appearance"), _
         DefaultValue("0.00"), _
         Description("The price of the book."), _
         Localizable(True) _
         > _
         PublicOverridableProperty Price() AsDecimalGetDim p AsObject = ViewState("Price")
                If p IsNothingThen p = Decimal.Zero
                ReturnCType(p, Decimal)
            EndGetSet(ByVal value AsDecimal)
                ViewState("Price") = value
            EndSetEndProperty

        < _
        Bindable(True), _
        Category("Appearance"), _
        DefaultValue(""), _
        Description("The title of the book."), _
        Localizable(True) _
        > _
        PublicOverridableProperty Title() AsStringGetDim s AsString = CStr(ViewState("Title"))
                If s IsNothingThen s = String.Empty
                Return s
            EndGetSet(ByVal value AsString)
                ViewState("Title") = value
            EndSetEndPropertyProtectedOverridesSub 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()
        EndSub

#Region "state management"ProtectedOverridesSub LoadViewState( _
            ByVal savedState AsObject)
            Dim p As Pair = TryCast(savedState, Pair)
            If p IsNotNothingThenMyBase.LoadViewState(p.First)
                CType(Author, IStateManager).LoadViewState(p.Second)
                ReturnEndIfMyBase.LoadViewState(savedState)
        EndSubProtectedOverridesFunction SaveViewState() AsObjectDim baseState AsObject = MyBase.SaveViewState
            Dim thisState AsObject = NothingIf authorValue IsNotNothingThen
                thisState = _
                    CType(authorValue, IStateManager).SaveViewState()
            EndIfIf thisState IsNotNothingThenReturnNew Pair(baseState, thisState)
            ElseReturn baseState
            EndIfEndFunctionProtectedOverridesSub TrackViewState()
            If authorValue IsNotNothingThenCType(Author, IStateManager).TrackViewState()
            EndIfMyBase.TrackViewState()
        EndSub
#End Region

    EndClassEndNamespace
// BookNew.csusing 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>")
    ]
    publicclass BookNew : WebControl
    {
        private StateManagedAuthor authorValue;

        [
        Bindable(true),
        Category("Appearance"),
        DefaultValue(""),
        Description("The name of the author."),
        DesignerSerializationVisibility(
            DesignerSerializationVisibility.Content),
        PersistenceMode(PersistenceMode.InnerProperty)
        ]
        publicvirtual 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"),
        ]
        publicvirtual 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)
        ]
        publicvirtualstring 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)
        ]
        publicvirtual 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)
        ]
        publicvirtualstring Title
        {
            get
            {
                string s = (string)ViewState["Title"];
                return (s == null) ? String.Empty : s;
            }
            set
            {
                ViewState["Title"] = value;
            }
        }

        protectedoverridevoid 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
        protectedoverridevoid LoadViewState(object savedState)
        {
            Pair p = savedState as Pair;
            if (p != null)
            {
                base.LoadViewState(p.First);
                ((IStateManager)Author).LoadViewState(p.Second);
                return;
            }
            base.LoadViewState(savedState);
        }

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

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

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

        }

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

    }
}

Code Discussion

The BookNew control demonstrates the pattern for implementing properties whose types manage their own state by implementing the IStateManager interface. While examining the code for the BookNew control in this topic, you might find it useful to also examine the code for the StateManagedAuthor type, the type of the BookNew control's Author property. The code listing for StateManagedAuthor is in the Custom Type State Management Example topic.

BookNew defines the Author property as a read-only property, stored in a private field of type StateManagedAuthor. In the Author property accessor, if the private field corresponding to the property is null (Nothing in Visual Basic), BookNew assigns a new StateManagedAuthor object to the private field. If BookNew has started tracking state, BookNew initiates state tracking on the newly created StateManagedAuthor object by invoking the object's TrackViewState method. For more information about tracking, see Server Control Properties Example.

The Author property participates in state management by calling the IStateManager methods of the StateManagedAuthor object from its own state management methods: TrackViewState, SaveViewState, and LoadViewState.

In the overridden TrackViewState method, BookNew calls the TrackViewState method of the base class and the TrackViewState method of the StateManagedAuthor object that corresponds to the Author property.

In the overridden SaveViewState method, BookNew invokes the SaveViewState method of the base class and the SaveViewState method of the StateManagedAuthor object that corresponds to the Author property. If the Author property has state to save, the BookNew control's SaveViewState method returns a Pair object that contains the state of the base class and of the Author property. If the Author property does not have state to save, the method returns only the state returned by the SaveViewState call to the base class. Based on the number of custom properties that contribute state, you should return objects of type Pair, Triplet, or Array from SaveViewState. This enables you to retrieve the different parts of the saved state more easily in the LoadViewState method. In this case, the Pair class is used, because there are two items, the base class state and the Author state.

In the overridden LoadViewState method, BookNew implements the inverse of the operations that it implemented in the LoadViewState method. BookNew loads state into the base class and into the Author property, or, if the Author property did not have state to save, BookNew loads state into only the base class. You should always call the LoadViewState method of the base class, even if the saved state is null (Nothing in Visual Basic), because the base class might have implemented other logic in this method when it does not have state to restore.

Test Page for the BookNew Control

The following example shows an .aspx page that uses the BookNew control.

<%@ 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>

Building and Using the Example

Compile the BookNew control with the StateManagedAuthor class and the StateManagedAuthorConverter class described in Custom Type State Management Example.

For more information about building the control and using it in a page, see Building the Custom Server Control Examples.

See Also

Concepts

Custom Type State Management Example

Server Control Properties Example

Other Resources

Developing Custom ASP.NET Server Controls