Introduction
When dynamically adding controls to an ASP.NET page in runtime the object
references are lost at postback because they have no handle in the codebehind.
The values entered by the user is not availible when accessing these objects
after postback, and they seem empty. This article describes how to use
ViewState to recreate and reinsert the postback values into the objects to
access their values.
Background
An ASP.NET application with pages that use dynamic generation of controls that
need to retain state across postbacks. The solution described in this paper
enables you to create a totally dynamic number of controls at runtime and
retreive their values after postback.
Solution
Dynamically added controls have no object reference variable in the codebehind
class. They appear only in the control collection of the containing control,
i.e. the Page.Controls
collection. When the page is posted back to the server
as a result of user interaction a new instance of the codebehind class is
instantiated, and all the variables of the class is set with values from the
ViewState.
This means that the objects we are accessing from the codebehind class, that
"feels" like the same objects as we worked on before postback, actually are new
ones that got their predecessors values via ViewState and ASP.NET state
management.
So, the controls that were dynamically created are no longer there and
consequently the values returned from these controls have no place to go. They
are lost in the viewstate.
In order to catch these values the dynamically generated controls needs to
be re-generated at Page_Load. The important thing is to assign the
same ID to each control. The ViewState uses the ID property of the Control
objects to reinstate the values.
Add the following elements to your System.UI.Page
class:
public class DynamicallyAddingControls : System.Web.UI.Page
{
protected int NumberOfControls
{
get{return (int)ViewState["NumControls"];}
set{ViewState["NumControls"] = value;}
}
private void Page_Load(object sender, System.EventArgs e)
{
if(!Page.IsPostBack)
this.NumberOfControls = 0;
else
this.createControls();
}
private void createControls()
{
int count = this.NumberOfControls;
for(int i = 0; i < count; i++)
{
TextBox tx = new TextBox();
tx.ID = "ControlID_" + i.ToString();
Page.Controls.Add(tx);
}
}
private void addSomeControl()
{
TextBox tx = new TextBox();
tx.ID = "ControlID_" + NumberOfControls.ToString();
Page.Controls.Add(tx);
this.NumberOfControls++;
}
}
Note that the createControls
method has to simulate the way that
you dynamically built your page before the postback. The important thing here
is obviously to assign identical ID values to the correct type of controls to
that we can access them at postback.
Points of Interest
This solution works because the
ASP.NET ViewState supports dynamically added controls, but does not do the
re-generation for us. As long as the ID properties match ASP.NET does the rest
of the job for us.
Thanks to Eric S�tter for
providing valuable input on this article!