Introduction:
I would like to present a small web application which allows us to create TextBoxes dynamically and access these TextBoxes at codebehind. These dynamic TextBoxes also retain their values during PostBacks.
This article shows an easy and light way to implement the functionality.
Strategy:
The Container:
We will use a Div element with attribute runat="Server", so that we can access it at codebehind.
This Div will serve as the container of our dynamic TextBoxes. We will use the Controls collection of this Div to add dynamically generated TextBoxes.
The Regenerator:
Since controls created dynamically at runtime are lost on PostBack, so we need to regenerate all the dynamic TextBoxes at PageLoad.
So, the question is how we can make controls, once created, available at next PostBack; simple, we can use session or viewstate bag of our page.
Saving all these controls in session or viewstate can cause a performance hit, what to do now? Since ASP.Net maintains state of its controls depending upon a unique Id, so if we save only the Id's of these controls and regenerate controls using the same Id's as last PostBack we are done.
Now, between session and viewstate, to save a list of all the Id's, we will choose viewstate because it is specific to a web page. And its scope is limited to the page's life.
The Accessor:
Once we have all the dynamic controls in our container, we can make use of its Controls collection to iterate through our TextBoxes and access their values.
Using The Code:
The User Interface:
The page design is very simple, it contains one container Div and two Buttons to trigger the event of "Creating TextBoxes" and "Accessing their values". It is as simple as:
<div>
<asp:LinkButton ID="lbnAddNew" runat="server" Text="Add New"
OnClick="lbnAddNew_Click"></asp:LinkButton>
</div>
<div id="divRT" runat="server">
</div>
<div>
<asp:Button ID="btnAccessValues" Text="save" runat="Server"
OnClick="btnAccessValues_Click" />
</div>
Creating Dynamic TextBoxes:
When a new TextBox is created, we will save its Id to our List of Strings (List<string> present in viewstate. Hence first thing to do is to create a unique Id for our newly generated TextBox.
Here we generate new Id by incrementing the suffix integer of Id of last generated TextBox.
List<string> lstDynId= (List<string>)ViewState[strVS_DynamicIds];
int iUnique = 0;
//get the Id of last textbox
string strLastControlId = lstDynId[lstDynId.Count - 1];
// get the substring starting after "tbx"
string strIdNumber = strLastControlId.Substring(3);
iUnique = int.Parse(strIdNumber) + 1;
Then we create a new TextBox, assign this unique Id to it, and add this TextBox to our container Div and it's Id to our list of All the Id's saved in viewstate.
Following is the code to put all these things together.
protected void lbnAddNew_Click(object sender, EventArgs e)
{
List<string> lstDynId;
int iUnique = 0;
string strDynId = "tbx";
if (ViewState[strVS_DynamicIds] != null)
{
lstDynId = (List<string>)ViewState[strVS_DynamicIds];
//get the Id of last textbox
string strLastControlId = lstDynId[lstDynId.Count - 1];
// get the substring starting after "tbx"
string strIdNumber = strLastControlId.Substring(3);
iUnique = int.Parse(strIdNumber) + 1;
}
else
{
lstDynId = new List<string>();
}
strDynId += iUnique;
TextBox tbx = new TextBox();
tbx.ID = strDynId;
divRT.Controls.Add(tbx);
lstDynId.Add(strDynId);
ViewState[strVS_DynamicIds] = lstDynId;
}
Regenerating TextBoxes at PostBack:
This task is quite simple, once we have a list of Id's saved in viewstate we can iterate through it and regenerate TextBoxes with these Id's.
private void DisplayRTControls()
{
if (ViewState[strVS_DynamicIds] != null)
{
List<string> lstDynId = (List<string>)ViewState[strVS_DynamicIds];
foreach (string strId in lstDynId)
{
TextBox tbx = new TextBox();
tbx.ID = strId;
divRT.Controls.Add(tbx);
}
}
}
Now, we just need to call this function at PageLoad.
Accessing the Dynamic TextBoxes at CodeBehind:
Since our dynamic TextBoxes are added to our container Div at PageLoad, we can access these TextBoxes by iterating through the Controls collection of the container Div. As:
protected void btnAccessValues_Click(object sender, EventArgs e)
{
if (ViewState[strVS_DynamicIds] != null)
{
List<string> lstDynId = (List<string>)ViewState[strVS_DynamicIds];
foreach (string strId in lstDynId)
{
TextBox tbx = (TextBox)divRT.FindControl(strId);
Response.Write(tbx.Text);
}
}
}
This concludes the article. I hope it could be helpful to someone.