Tuesday, July 31, 2007

Hidden Controls and ViewState

I don't know if it is obvious how important ViewState is for hidden controls.  I would like to stress where ViewState plays important role for hidden controls (not visible) as it often leads to not obvious problems.

If you like to explore how different ASP.NET controls use ViewState to store their data, Nikhil Kothari's Web Development Helper is a very helpful tool.  I definitely recommend to download and install it, if you like to know what is in your ViewState.  

TextBox when placed on a web form usually does not require ViewState to be enabled to provide its core functionality "being input box".  You can check that __VIEWSTATE hidden field is the same across post-backs if you change the value in your TextBox on the following form:

    <form id="form1" runat="server">
<div>
<asp:TextBox runat="server" ID="TextBox1"></asp:TextBox>
<asp:TextBox runat="server" ID="TextBox2"></asp:TextBox>
<asp:Button runat="server" ID="Submit" Text="Submit" />
</div>
</form>

ASP.NET does not store value of the Text property of TextBox in the ViewState, because its value is submitted by the <input type=text> to the server on each post-back.  (ASP.NET does save Text property into ViewState if TextChanged event has at least one event handler.  This is required to compare currently submitted value with a previous value and raise event only when the value has changed).


However, when TextBox control is not visible or it is placed in any not visible control, TextBox controls does not render <input type=text> to the Html writer and ViewState plays its important role.  Invisible TextBox controls save their Text property as all other properties in its ViewState collection. 


It is easy to see how disabled ViewState impacts behavior of:

<asp:MultiView runat="server" ID="MultiView">
<asp:View runat="server" ID="View1">
<asp:Button runat="server" ID="SwitchToNextButton" Text="Next" OnClick="SwitchToNextButton_Click" />
<asp:TextBox runat="server" ID="TextBox" />
</asp:View>
<asp:View runat="server" ID="View2">
<asp:Button runat="server" ID="SwitchToPreviousButton" Text="Previous" OnClick="SwitchToPreviousButton_Click" />
</asp:View>
</
asp:MultiView>
<
asp:Button runat="server" ID="Button" Text="Postback" />
    protected void SwitchToNextButton_Click(object sender, EventArgs e)
{
MultiView.SetActiveView(View2);
}

protected void SwitchToPreviousButton_Click(object sender, EventArgs e)
{
MultiView.SetActiveView(View1);
}

You can type some text in the TextBox and switch to another View in the MultiView.  Then, if you click "Previous" button, the first View appears and TextBox control shows text you have typed.


If you disable ViewState for the MultiView (and thus for all its children), TextBox keeps showing your text only while it is visible.  Once you hide it by switching to another view, TextBox becomes empty.


Be accurate when disabling ViewState for a whole page or for a large part of the page, if you don't know what controls exactly will be placed there.

2 comments:

Anonymous said...

So, in reality, whether you set the Visible property of a control to True or False, it is still using View State? So if I show and hide 6 panels on a form, they are always being stored in View State?

This gets confusing because I always thought if the control isn't visible, it doesn't render it nor use view state...

Thanks.

Anonymous said...

Bit late in the game but:
It must store ViewState when invisible as its properties are still accessible and maintained between page post backs. When visible it will use the existing input elements through normal form posting. When invisible, these input HTML elements are no longer rendered, so their state must be maintained in the ViewState. Otherwise when you programmatically alter its properties (such as text) these changes won't be transferred to the next post back.

This is only applicable for controls that use HTML input fields though -- controls such as GridViews, labels, hyperlinks, etc would still use viewstate as they have no corresponding HTML input fields that get posted back through the form.