RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Building a PreserveProperty Control in ASP.NET 2.0 : Page 3

Find out how to create a deterministic and declarative property persistence control that works without ViewState and provides transparent access to persisted properties and fields on your ASP.NET controls and pages.

How the PreserveProperty Control Works
The implementation of the control is pretty simple. It has a PreservedProperties collection that holds the ControlID (or instance if available) and the property name. When you call the PreserveProperty() method on the control or declaratively define the control on a page, each ControlId and Property name is stored in the collection. The collection is a Generic List. I love generics for this stuff—no more creating custom collections for child controls!

To get the collection to work as a designable collection you have to use a few custom attributes on the Control class as well as the collection property. You also need to implement AddParsedSubObject (or use the DefaultProperty attribute if you only have a single collection) to get the child control values to be added as PreservedProperty objects from the declarative script definition. Listing 1 shows the class and collection definition.

The code deals with storing the PreservedProperties in a simple strongly-typed List collection. The control uses a custom class to hold the control's ID, an instance reference if available, and the ID for the control. The PreservedProperties collection is a temporary holding container for the property identification; the values are not actually stored in it until later in the request cycle.

Encoding and Decoding the Persisted Data
The actual hooks for encoding and decoding depend on the StorageMode which includes ControlState, HiddenVariable, SessionVariable, and CachePerPage. All but ControlState require explicit hooks to fire for the encoding and decoding to occur. In these modes, hook calls are made in OnInit() and OnPreRender() of the control. OnInit() fires very early in the page cycle so that the preserved value can be retrieved prior to any other state retrieval. Specifically, the property value is set before ViewState assigns its value or before a postback value is assigned. This makes preserved properties have the lowest priority in value assignment, which is the intended behavior.

The PreserveProperty control lets you work with properties and fields without having to worry about the persistence mechanism.
When the value is stored it's done in the As part of the PreservePropertyControl.OnPreRender().

ControlState Persistance in ASP.NET 2.0
ControlState is a new feature of ASP.NET 2.0. It's meant as a control internal state implementation used to store essential data between page postbacks. It uses ViewState for storage, but unlike stock ViewState it is not affected by the setting of EnableViewState and always writes out its values.

You can easily work with ControlState by implementing two methods on the Page class: SaveControlState and LoadControlState. These methods work by returning and retrieving an object value that ASP.NET persists internally. These objects must either be simple types, serializable, or implement a TypeConverter. As with ViewState, the rules are determined through the .NET LosFormatter class, which is an optimized serializer ASP.NET uses for encoding ViewState strings. You can find ControlState in the System.Web.UI namespace.

To enable ControlState you have to tell the page to use it, for example:

You'd typically call this in the OnInit() method of a control.

You then override SaveControlState() to return an object that contains the state. If you have more than one value to persist, a typical object is a Hashtable with all the persisted values in it. When the page posts back, LoadControlState is called with an object parameter that essentially restores that object saved in SaveControlState. It's a very easy mechanism that deals with all the encoding details. All you do is return an object and off you go. Listing 2 shows the SaveControlState() and LoadControlState() methods for managing ControlState.

SaveControlState() walks through its PreservedProperties collection and starts by finding each control instance. If you used code to add properties, then you likely passed in a control instance reference, but when using declarative script a string reference is stored, and you'll need to use FindControl to actually locate the control. Once a control reference is available the value for the property is retrieved via Reflection. Note the flags to retrieve both fields and properties and both public and non-public members. Also note that you cannot preserve private members on a Page object.

The next step is to add the value to a Hashtable with the key being a concatenation of the unique ControlID and the property name. Hashtables are efficient at storing key value pairs and persist in a lightweight fashion. The SaveControlState method then returns this Hashtable for persistence.

Loading the data on a postback works this process in reverse. LoadControlState() receives the Hashtable as an input and then runs through the collection, retrieving each key and value. The code in LoadControlState() splits the key back into its ControlID and property name components and FindControl is then used to get an instance, followed by Reflection to set the control's value.

This is a very straightforward process and using ControlState takes very little code to implement this solution.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date