Many times these questions are asked

1.     How to create Dynamic Controls?

2.     Why dynamic controls lost after postback?

3.     How to get values of Dynamic Controls on form submit?

4.     How to retain values of Dynamic Controls?

5.     How to use Dynamic Controls with Master Pages?

6.     How to add Event Handler to Dynamic Control?

 

Below article answers all these questions.

Here I will explain Dynamic Controls using a completely dynamic page with no controls on it.

 

Dynamic Controls

 

Dynamic Controls are created at runtime and then added to a control which already resides on the page which acts as a parent control or container.

 

Create a Dynamic Control

 

Below I have created a Dynamic Button

 

C#

Button btnSubmit = new Button();

btnSubmit.ID = "btnSubmit";

btnSubmit.Text = "Submit";

 

VB.Net

 

Dim btnSubmit As New Button()

btnSubmit.ID = "btnSubmit"

btnSubmit.Text = "Submit"

 

 

Add Event Handler

 

Below I am adding an OnClick Event Handler to the Dynamic Button. When the button is clicked the

btnSubmit_Click will be invoked.

 

C#

btnSubmit.Click += new System.EventHandler(btnSubmit_Click);


VB.Net

AddHandler btnSubmit.Click, AddressOf btnSubmit_Click

 

 

  

Event Handler

 

It is necessary that you create an Event Handler before assigning it to the Dynamic Control to avoid Compilation Error.

 

C#

protected void btnSubmit_Click(object sender, EventArgs e)

{

    //OnClick Event Handler for btnSubmit

}

 

VB.Net

Protected Sub btnSubmit_Click(ByVal sender As Object, ByVal e As EventArgs)

    'OnClick Event Handler for btnSubmit

End Sub

 

Add the Control on the Page

 

Finally you need to add the Dynamic Control to the Page. In the code below I am adding the dynamic button to the form.

 

C#

this.form1.Controls.Add(btnSubmit);

 

VB.Net

Me.form1.Controls.Add(btnSubmit)

 

Dynamic Controls with Master Pages

 

When using master pages there is no form in the content pages. So the question arises where to add the dynamic controls. The answer is ContentPlaceHolder.

Below code explains how to get the ContentPlaceHolder reference in the Content Page using its ID.

 

C#

ContentPlaceHolder content = (ContentPlaceHolder)this.Master.FindControl("ContentPlaceHolder1");

 

VB.Net

Dim content As ContentPlaceHolder = DirectCast(Me.Master.FindControl("ContentPlaceHolder1"), ContentPlaceHolder)

 

 

Now the only difference between normal pages and the master pages is that instead of adding the dynamic controls to the master page you will need to add the controls to the ContentPlaceHolder whose reference you’ve got above. See the code below

 

C#

content.Controls.Add(btnSubmit);

 

VB.Net

content.Controls.Add(btnSubmit)

 

Rest everything will be the same.

 

Dynamic Controls need to be created each time the page is sent to the server, so that they reappear on the page after postback.  Many times people do a mistake is they put the code that creates and adds dynamic controls in the Not isPostBack condition. In this way the dynamic controls are created only first time the page is loaded since the condition is true. But when there’s a postback by some control the dynamic controls are not created since the condition is false.

So to avoid it the code for creating dynamic controls must be placed outside all conditional blocks in the page load.

 

Now since you have learnt how to create Dynamic Controls we’ll move a step ahead.

To start with I’ll add a dynamic Panel which will act as a container for my dynamic textboxes

 

C#

//Dynamic TextBox Panel

pnlTextBox = new Panel();

pnlTextBox.ID = "pnlTextBox";

pnlTextBox.BorderWidth = 1;

pnlTextBox.Width = 300;

this.form1.Controls.Add(pnlTextBox);

 

 

   

VB.Net

'Dynamic TextBox Panel

pnlTextBox = New Panel()

pnlTextBox.ID = "pnlTextBox"

pnlTextBox.BorderWidth = 1

pnlTextBox.Width = 300

Me.form1.Controls.Add(pnlTextBox)

 

 

Then I will add a Dynamic Button whose job will be creating Dynamic TextBoxes.

 

C#

//Button To add TextBoxes

Button btnAddTxt = new Button();

btnAddTxt.ID = "btnAddTxt";

btnAddTxt.Text = "Add TextBox";

btnAddTxt.Click += new System.EventHandler(btnAdd_Click);

this.form1.Controls.Add(btnAddTxt);

 

VB.Net

'Button To add TextBoxes

Dim btnAddTxt As New Button()

btnAddTxt.ID = "btnAddTxt"

btnAddTxt.Text = "Add TextBox"

AddHandler btnAddTxt.Click, AddressOf btnAdd_Click

Me.form1.Controls.Add(btnAddTxt)

 

The Event Handler btnAdd_Click adds the dynamic TextBoxes to the page.

Now inorder to keep track of the dynamic buttons you will need to follow some prefixes for  the ID of the textboxes.

 

Here I am using prefex txtDynamic for IDs of all the dynamic textboxes. So the first textbox will

txtDynamic-1,  the second will be txtDymanic-2 and so on.

This will help us to identify the textboxes and also retreive their values. The textbox is created and added to the pnlTextBox Panel which I created in order to act as a placeholder for the dynamic textboxes.

 

      

C#

protected void btnAdd_Click(object sender, EventArgs e)

{

    Button btn = (Button)sender;

    if (btn.ID == "btnAddTxt")

    {

        int cnt = FindOccurence("txtDynamic");

        TextBox txt = new TextBox();

        txt.ID = "txtDynamic-" + Convert.ToString(cnt + 1);

        pnlTextBox.Controls.Add(txt);

    }

}

 

VB.Net

Protected Sub btnAdd_Click(ByVal sender As Object, ByVal e As EventArgs)

   Dim btn As Button = DirectCast(sender, Button)

   If btn.ID = "btnAddTxt" Then

      Dim cnt As Integer = FindOccurence("txtDynamic")

      Dim txt As New TextBox()

      txt.ID = "txtDynamic-" & Convert.ToString(cnt + 1)

      pnlTextBox.Controls.Add(txt)

   End If                                                                  End Sub

 

 

You will notice that I am using a variable cnt and a function FindOccurence.

The FindOccurence function simply calculates the count of occurences of the substring that is passed to it in the Request.Form collection. In the above code, I am passing the substring txtDynamic hence it gives me the count of the existing dynamic textboxes. Hence the next textbox will have ID greater than the total count i.e. cnt + 1.

 

C#

private int FindOccurence(string substr)

{

    string reqstr = Request.Form.ToString();

    return ((reqstr.Length - reqstr.Replace(substr, "").Length)

            /  substr.Length);

}

 

VB.Net

Private Function FindOccurence(ByVal substr As String) As Integer

   Dim reqstr As String = Request.Form.ToString()

   Return ((reqstr.Length - reqstr.Replace(substr, "").Length)

         / substr.Length)

End Function

 

 

Now when you click the add button there’s a postback thus all the controls need to be recreated plus you reassign them their values

The RecreateControls function does this job. It accepts the following parameters

1.     ctrlPrefix – The prefix used for the controls e.g. txtDynamic, ddlDynamic

2.     ctrlType -   The type of control TextBox, DropDownList

 

So based on the controls you need to pass the appropriate values.

 

Here I am creating TextBoxes So I will call the function as follows

 

 

C#

if (IsPostBack)

{

    RecreateControls("txtDynamic", "TextBox");

}

 

 

VB.Net

 

If IsPostBack Then

   RecreateControls("txtDynamic", "TextBox")

End If

 

 

Note that I am calling the function in the isPostBack Condition the reason for doing this is that the controls should only be recreated only on postback.

 

RecreateControls function

 

First I check how many controls of that prefix are there in the Request.Form Collection. Below I’ll show how the Reqeust.Forms Collection stores the value in it So that you’ll understand the logic for pulling values back better. See the figure below.


Request.Form Collection

In the Text Visaualizer Figure you’ll notice that the controls are separated by ampersand (&) and the controls name and the value are separated by Equal to Sign (=) in the following manner.

txtDynamic-1=&txtDynamic-2=&txtDynamic-3=&txtDynamic-4...

 

For that I will split the Request.Form collection based on the ampersand character (&) and also find the occurrence of the prefix in the collection. Refer the code below

 

C#

string[] ctrls = Request.Form.ToString().Split('&');

int cnt = FindOccurence(ctrlPrefix);

 

VB.Net

Dim ctrls As String() = Request.Form.ToString().Split("&"c)

Dim cnt As Integer = FindOccurence(ctrlPrefix)

 

Then I am looping through the all the elements in the Request.Form Collection and the count of the prefixes based on the value returned by the FindOccurence function and matching each prefix with the Request.Form element to get the values on the TextBoxes and reassign them accordingly.

 

C#

private void RecreateControls(string ctrlPrefix, string ctrlType)

{

    string[] ctrls = Request.Form.ToString().Split('&');

    int cnt = FindOccurence(ctrlPrefix);

    if (cnt > 0)

    {

        Literal lt;

        for (int k = 1; k <= cnt; k++)

        {

            for (int i = 0; i < ctrls.Length; i++)

            {

                if (ctrls[i].Contains(ctrlPrefix + "-" + k.ToString()))

                {

                    string ctrlName = ctrls[i].Split('=')[0];

                    string ctrlValue = ctrls[i].Split('=')[1];

 

                    //Decode the Value

                    ctrlValue = Server.UrlDecode(ctrlValue);

 

                    if (ctrlType == "TextBox")

                    {

                        TextBox txt = new TextBox();

                        txt.ID = ctrlName;

                        txt.Text = ctrlValue;

                        pnlTextBox.Controls.Add(txt);

                    }

                    break;

                }

            }

        }

    }

}

 

 

             

VB.Net

Private Sub RecreateControls(ByVal ctrlPrefix As String,

ByVal ctrlType As String)

   Dim ctrls As String() = Request.Form.ToString().Split("&"c)

   Dim cnt As Integer = FindOccurence(ctrlPrefix)

   If cnt > 0 Then

      Dim lt As Literal

        For k As Integer = 1 To cnt

          For i As Integer = 0 To ctrls.Length - 1

            If ctrls(i).Contains((ctrlPrefix & "-") + k.ToString()) Then

              Dim ctrlName As String = ctrls(i).Split("="c)(0)

              Dim ctrlValue As String = ctrls(i).Split("="c)(1)

 

              'Decode the Value

               ctrlValue = Server.UrlDecode(ctrlValue)

 

 

               If ctrlType = "TextBox" Then

                 Dim txt As New TextBox()

                 txt.ID = ctrlName

                 txt.Text = ctrlValue

                 pnlTextBox.Controls.Add(txt)

               End If

             Exit For

            End If

          Next

        Next

    End If

 End Sub

 

In the above code the variables ctrlName and ctrlValue gives the Name and the Value of the Control respectively.

Based on the captured ID and the value the control is then recreated. Thus retaining its value across postbacks

See how it works in the animated figure below.



Dynamic Controls retain values across postback

I have done the same with DropDownList also and you’ll find the code for the same in the attached source code

The source code is available in VB.Net and C# Download it here.


DynamicControls.zip (8.52 kb)