Introduction
This article aims at understanding why and when we need to have ControlState
for the state management. We also try to understand the same with a very basic implementation of control state.
Background
By default, the ASP.NET page has EnableViewState
property true
. This makes ASP.NET automatically keep track of state of all the controls present on the page. Now if I am working on a web page where I know all the controls will be dynamically bound to some data on each postback, I don't have to keep track of the old information for the controls. So I might decide to turn it off. Now this is a perfectly good choice for the page developer but things could get messy if the same page contains a custom control and that custom control is using ViewState
to manage the data inside the control.
The main focus here is to look at from a Control Developers point of view. How can I write controls that are immune to the controls users' action, i.e., it will work in any case whether ViewState
is ASP.NET enabled or disabled.
Using the Code
ASP.NET already provides a mechanism for such scenarios and it's called ControlState
. Here we will simply try to see the right way of writing a custom control with proper ControlState
and ViewState
management.
Suppose we have a very simple custom control that displays a couple of welcome messages to the user. If I go and create a custom control project to facilitate this, I will get something like:
[ToolboxData("<{0}:WebCustomControl runat="server"></{0}:WebCustomControl>")]
public class WebCustomControl : WebControl
{
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
public string Text
{
get
{
String s = (String)ViewState["Text"];
return ((s == null) ? String.Empty : s);
}
set
{
ViewState["Text"] = value;
}
}
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
public string Text2
{
get
{
String s = (String)ViewState["Text2"];
return ((s == null) ? String.Empty : s);
}
set
{
ViewState["Text2"] = value;
}
}
protected override void RenderContents(HtmlTextWriter output)
{
output.Write(Text);
output.Write("<br/>");
output.Write(Text2);
output.Write("<br/>");
}
}
A very basic control that is rendering two welcome messages and the user of the control has an option of setting these messages from outside, which could be from a database call or reading from a file. The user will perhaps do this only once and will expect our control to remember these string
s. So let's say the user of the controls is doing something like:
if (IsPostBack == false)
{
WebCustomControl_1.Text = "This is a dummy Text";
WebCustomControl_1.Text2 = "This is another dummy Text";
}
Now for the first run, he will do the property setting and from next time onwards, he leaves it upto the control to render these things. Now the page still has EnableViewState
property set to "true
". So if we run the page and do postback, we will observe the expected behavior. Let's look at what user will see:
Now if the user disables the viewstate
for the page or even for our custom control when a postback occurs:
The values are gone, the reason being our control depends on ViewState
to function and we need to remove this dependency to controlState
so that even in this scenario, our control will continue to work.
So let us use Control State for one line of text and not for other (purely to see how these things differ and we can compare the right way and the wrong way in the same piece of code, ideally all the controls information should use ControlState
mechanism).
What we need to do here is, we have to override the OnInit
method and call the RegisterRequiresControlState
method during initialization. Then we have to override the SaveControlState
and LoadControlState
methods. So let us see how we do that for using ControlState
for Text
property of our control.
protected override void OnInit(EventArgs e)
{
Page.RegisterRequiresControlState(this);
base.OnInit(e);
}
protected override void LoadControlState(object savedState)
{
Text = (string)savedState;
}
protected override object SaveControlState()
{
return Text;
}
Now we have the first property of our control using controlState
and the second one not using it. Now on postback, the output is:
Look at the code to see the difference. The right way would be the way ControlState
is being used for the first property, it should be used for all the controls inside a custom control.
Points of Interest
To summarize, we saw what is the control state and how to enable it in custom controls. The control state takes away the decision of a developer whether to use ViewState
or not. Whenever we want to use the control state, you should think whether to implement it or give the decision of how to save the state information to the developers that use your control. The second choice is more preferable as it decreases the dependency on something that Page
can set.
History
- 17 Feb 2012: Explanatory tutorial on
ControlState