This is a common issue and it's related to the page life cycle:
Take a look at the following questions:
Click events on Array of buttons
Button array disappears after click event
Dynamically create an ImageButton
Now the basic steps to remember when creating dynamic controls are:
- Dynamic controls should be created in the
PreInit
event when you are not working with a master page, if you are, then create the controls in the Init
event
- Avoid setting properties that can be changed in each post in these events because when the view state is applied (in a post event) the properties will be overridden
- Dynamic controls must be created every time the page is posted, avoid this
if(!this.IsPostBack) this.CreatemyDynamicControls();
- When you create the controls in the
PreInit
or Init
events, their states will be automatically set in a post event, which means in the LoadComplete
event your controls will contain their state back even when you create them again in each post and even when you did not explicitly set their state. Note this behavior is different when you are dealing with controls created at design time, in that case, the event where the state has been set is the Load event
- Event subscription should occur before the
PageLoadComplete
or they will not be raised
Consider the following description from MSDN
If controls are created dynamically at run time or declaratively within templates of data-bound controls, their events are initially not synchronized with those of other controls on the page. For example, for a control that is added at run time, the Init and Load events might occur much later in the page life cycle than the same events for controls created declaratively. Therefore, from the time that they are instantiated, dynamically added controls and controls in templates raise their events one after the other until they have caught up to the event during which it was added to the Controls collection.
The above is not so clear to me, but I have found the following. The following TextBox
's are created at design time
protected void Page_PreInit(object sender, EventArgs e)
{
this.txtDesignTextBox1.Text = "From PreInit";
this.txtDesignTextBox1.Text += DateTime.Now.ToString();
}
protected void Page_Init(object sender, EventArgs e)
{
this.txtDesignTextBox2.Text = "From Init";
this.txtDesignTextBox2.Text += DateTime.Now.ToString();
}
protected void Page_Load(object sender, EventArgs e)
{
this.txtDesignTextBox3.Text = "From Load";
this.txtDesignTextBox3.Text += DateTime.Now.ToString();
}
At first sight you might think that in every post all the textboxes are updated with the current date, but this is not the case, since they were created at design time they follow strictly the ASP.Net page life-cycle which means, their state is overriden after the PreInit and Init events, only the txtDesignTextBox3
is updated in every post because its Text
property is updated after the view state has been set (in the Load
event).
But with dynamic controls the behavior is different, remember the MSDN description:
for a control that is added at run time, the Init and Load events might occur much later in the page life cycle
Consider the following:
protected void Page_PreInit(object sender, EventArgs e)
{
var textBox = new TextBox { Text = "From PreInit", Width = new Unit("100%") };
textBox.Text += DateTime.Now.ToString();
this.myPlaceHolder.Controls.Add(textBox);
}
protected void Page_Init(object sender, EventArgs e)
{
var textBox = new TextBox { Text = "From Init", Width = new Unit("100%") };
textBox.Text += DateTime.Now.ToString();
this.myPlaceHolder.Controls.Add(textBox);
}
protected void Page_Load(object sender, EventArgs e)
{
var textBox = new TextBox { Text = "From Load", Width = new Unit("100%") };
textBox.Text += DateTime.Now.ToString();
this.myPlaceHolder.Controls.Add(textBox);
}
In this case, the controls behave slightly different, in this case, in each post, the controls are never updated not even the controls created in the Load
event
The reason is their life-cycle events occurs much later in the page-life cycle which means their state is overridden even after the Load event
To solve this, you can use the LoadComplete
event, in this event you can change the state of dynamic controls:
protected void Page_LoadComplete(object sender, EventArgs e)
{
var textBox = new TextBox { Text = "From LoadComplete", Width = new Unit("100%") };
textBox.Text += DateTime.Now.ToString();
this.myPlaceHolder.Controls.Add(textBox);
}
In this case, the state will be updated in each post.
However, take in consideration that you should subscribe to dynamic controls events, before the LoadComplete
event or they will not be raised.
... I know I hate this kind of behavior, that's why I love MVC
As a quick reference for controls created at design time: Notice how the LoadViewState
method is called after the PreInit
and Init
events but before the Load
event. The Load
event is considered stable because in this event you can access the view state of your controls. Also notice that the RaisePostBackEvent
method represent the control event that caused the post back, this can be, the SelectedIndexChanged
, Click
, etc this event is handled after the Load
event
For a complete detailed specification read the MSDN Page Life-Cycle documentation