This example shows how to create a custom control named IndexButton that uses control state to maintain critical state information across page requests. Control state, introduced in ASP.NET version 2.0, is similar to view state but functionally independent of view state. A page developer can disable view state for the page or for an individual control for performance. However, control state cannot be disabled. Control state is designed for storing a control's essential data (such as a pager control's page number) that must be available on postback to enable the control to function even when view state has been disabled. By default, the ASP.NET page framework stores control state in the page in the same hidden element in which it stores view state. Even if view state is disabled, or when state is managed using Session, control state travels to the client and back to the server in the page. On postback, ASP.NET deserializes the contents of the hidden element and loads control state into each control that is registered for control state.
The example illustrates a custom control that saves state in both control state and view state. In the example, the IndexButton control derives from the Button class and defines an Index property that it saves in control state. For comparison, IndexButton also defines an IndexInViewState property that it stores in the ViewState dictionary. To see the difference between control state and view state, use the IndexButton control as demonstrated in the .aspx page listed in the "Test Page for the IndexButton Control" section later in this topic.
Visual Basic
' IndexButton.vb
Option Strict On
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), _
ToolboxData("<{0}:IndexButton runat=""server""> ") _
> _
Public Class IndexButton
Inherits Button
Private indexValue As Integer
< _
Bindable(True), _
Category("Behavior"), _
DefaultValue(0), _
Description("The index stored in control state.") _
> _
Public Property Index() As Integer
Get
Return indexValue
End Get
Set(ByVal value As Integer)
indexValue = value
End Set
End Property
< _
Bindable(True), _
Category("Behavior"), _
DefaultValue(0), _
Description("The index stored in view state.") _
> _
Public Property IndexInViewState() As Integer
Get
Dim obj As Object = ViewState("IndexInViewState")
If obj Is Nothing Then obj = 0
Return CInt(obj)
End Get
Set(ByVal value As Integer)
ViewState("IndexInViewState") = value
End Set
End Property
Protected Overrides Sub OnInit(ByVal e As EventArgs)
MyBase.OnInit(e)
Page.RegisterRequiresControlState(Me)
End Sub
Protected Overrides Function SaveControlState() As Object
' Invoke the base class's method and
' get the contribution to control state
' from the base class.
' If the indexValue field is not zero
' and the base class's control state is not null,
' use Pair as a convenient data structure
' to efficiently save
' (and restore in LoadControlState)
' the two-part control state
' and restore it in LoadControlState.
Dim obj As Object = MyBase.SaveControlState()
If indexValue <> 0 Then
If obj IsNot Nothing Then
Return New Pair(obj, indexValue)
Else
Return indexValue
End If
Else
Return obj
End If
End Function
Protected Overrides Sub LoadControlState(ByVal state As Object)
If (state IsNot Nothing) Then
Dim p As Pair = TryCast(state, Pair)
If p IsNot Nothing Then
MyBase.LoadControlState(p.First)
indexValue = CInt(p.Second)
Else
If (TypeOf (state) Is Integer) Then
indexValue = CInt(state)
Else
MyBase.LoadControlState(state)
End If
End If
End If
End Sub
End Class
End Namespace
Some people think the
Still, it has its share of disadvantages. It sure can get bloated. Not only that, but disabling ViewState can wreack havock with the functionality of many controls.
This is why ASP.NET 2.0 introduces the control state. The basic idea is that there is some state that should be considered the data for the control, while other state is necessary for the control to function. For example, the contents of a GridView. The control doesn’t absolutely need this data persisted across postbacks to function properly. You could choose to reload it from the database,
In contrast is the state of the selected node in a
Unlike the
ViewState
is the spawn of the devil. Not one to be afraid of being in bed with the devil, I feel a tad bit less negative towards it, as it can be very useful.Still, it has its share of disadvantages. It sure can get bloated. Not only that, but disabling ViewState can wreack havock with the functionality of many controls.
This is why ASP.NET 2.0 introduces the control state. The basic idea is that there is some state that should be considered the data for the control, while other state is necessary for the control to function. For example, the contents of a GridView. The control doesn’t absolutely need this data persisted across postbacks to function properly. You could choose to reload it from the database,
Cache
, or Session
.In contrast is the state of the selected node in a
TreeView
. This is state that is necessary for the control to function properly across postbacks.Unlike the
ViewState
, the control state isn’t implemented as a property bag. You have to do a little bit of extra work to make use of it. Namely, there are two methods you have to implement in your custom control.LoadControlState
– Restores the control state from a previous page request. ASP.NET calls this method passing in the control state as an object to this method.SaveControlState
– Saves any changes to control state since the last post back. You need to return the state of the control as the return value of this method. ASP.NET will store it.
Page.RegisterRequireControlState
.A Demonstration That Makes This All Clear As Mud
I’ve put together a simple control to demonstrate the control state. Now before I go any further, I must warn you not to copy and paste this implementation. This implementation is designed to clarify how the control state works. I will present another implementation that describes a safer approach, which you can feel free to copy and paste. You’ll see what I mean.public class ControlStateDemo : WebControl
{
public int ViewPostCount
{
get { return (int)(ViewState["ViewProp"] ?? 0); }
set { ViewState["ViewProp"] = value; }
}
public int ControlPostCount
{
get { return controlPostCount; }
set { controlPostCount = value; }
}
private int controlPostCount;
protected override void OnInit(EventArgs e)
{
//Let the page know this control needs the control state.
Page.RegisterRequiresControlState(this);
base.OnInit(e);
}
protected override void OnLoad(EventArgs e)
{
ViewPostCount++;
ControlPostCount++;
base.OnLoad(e);
}
protected override void Render(HtmlTextWriter writer)
{
writer.Write("ViewState: "
+ this.ViewPostCount + "
");
writer.Write("ControlState:"
+ this.ControlPostCount + "");
base.Render(writer);
}
protected override void LoadControlState(object savedState)
{
int state = (int)(savedState ?? 0);
this.controlPostCount = state;
}
protected override object SaveControlState()
{
return controlPostCount;
}
}