In yesterday's post I blogged about problems with the viewstate after adding a control at runtime. A great thing with blogging are the responses, one by Martijn Boland inspired me to a more systematic investigation of the problem.
As a test bed I take a simple web form. It has one label, one textbox, a button, a checkbox and a panel. On creation I will add another textbox and another label from code. These controls are declared as privates in the code behind and they do not appear in the html of the aspx page. This dynamic addition is done twice, once in the OnInit event and once in the Page_Load.
private Label Label2;
private Label Label3;
private TextBox TextBox2;
private TextBox TextBox3;
#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
Label2 = new Label();
this.Controls.Add(Label2);
TextBox2 = new TextBox();
Panel1.Controls.Add(TextBox2);
InitializeComponent();
base.OnInit(e);
}
private void InitializeComponent()
{
....
}
#endregion
private void Page_Load(object sender, System.EventArgs e)
{
Label3 = new Label();
this.Controls.Add(Label3);
TextBox3 = new TextBox();
Panel1.Controls.Add(TextBox3);
}
Trying to add a textbox to the controls collection of the page itself will result in an error : Control '_ctl1' of type 'TextBox' must be placed inside a form tag with runat=server. Textboxes need a container control. Adding them to an existing panel will do.
Whether the viewstate of the dynamically created textboxes is working is easy to see. To test the viewstate of the labels I use the checkbox to conditionally update their text. This is done in the PreRender event.
private void WebForm1_PreRender(object sender, System.EventArgs e)
{
if (CheckBox1.Checked)
{
Label1.Text = TextBox1.Text;
Label2.Text = TextBox2.Text;
Label3.Text = TextBox3.Text;
}
}
What the demo will show is that the viewstate of all three control pairs, created in the designer, in the onInit and in the page_load does work. The contents and caption are preserved over roundtrips. This is actually what I did expect from the viewstate. As it has such a nice programming interface I expected the same flexible behaviour when adding controls. Nevertheless I ran into trouble with the viewstate when adding a literal control in the base webform of my app. The behaviour of the app became quite erratic and all debugging pointed to a wrecked viewstate. Martijn pointed me to the fact that it matters at which moment in the page lifecycle you add your control. I had done it in the page_load, moving the code to the OnInt fixed this. A closer look at the page life cycle made clear why this can make a difference.
The life cycle of a page goes through these steps
- Construct page
- Initialize (OnInit)
- Begin tracking Viewstate
- Load (Page_load)
- Prerender (OnPreRender)
- Save View state
- Render
- UnLoad (OnUnload)
You can hook in your own code using Onxxx events. To hook into other events you have to override the corresponding method. As you see the tracking of changes starts after the OnInit event. Anything done after that will interfere with maintaining the state. And can (as in my app) but will not always (as in the demo presented) wreck the state.
Peter