ASP.NET - Dynamic Controls

2. March 2011 19:18

This is a quick guide to show you away of creating as many dynamic controls as is required on a web page. For some reason a lot of developers typically seem to struggle when dealing with dynamic controls. They really are not that difficult to understand so long as you follow a few basic rules and understand a few myths about dynamic controls.

 

First off there is a myth about asp.net where dynamic controls appear to be difficult or impossible in certain situation's. Though I have been challanged by some of these situation it has always still be possible to create dynamic controls. The second thing that is important to understand is that all controls on a page are actually dynamic at some stage of the page lifecycle it just a matter of weather they are created by the code behind or by the framework parsing the aspx file and adding the correct controls to the page.

 

There are three simple rules that you must obey when using dynamic controls.

 

  1. The page must contain the same controls in the same order as they were added as all previoud postback's. This must be completed by the end of page load.
  2. Controls unless they are all named can never be removed from a page once they are added. Or the names given to the controls will get out of sync with the information stored on the viewstate. If this occurs you will see invalid viewstate error's. This happens when one control eg a button tries to load another control's viewstate eg a textbox.
  3. When the new control is added it must be on the page before it is devlivered to the client. Otherwise it will be missing its viewstate when the next post back happens.

 

 

What we are going todo for this simple example is to create a simple asp.net page with a label, drop down list, button, place holder. This will enable us to add enough functionality to add other controls of various types by selecting them in the drop down list and add them once the button is clicked. Of course any other event trigger could be used to add extra controls on the page. The purpose of the label is also to demonstrate the ability to bind an event (a button click) to one fo the dynamic controls to a function of our choice. The place holder is what we are using for a parent container for the dynamic controls.

 

So ... Let get started with a very basic asp.net page with the following code.

 

 

<div>
    <asp:Label runat="server" ID="lblInfo"></asp:Label><br />
    <asp:DropDownList runat="server" ID="ddlControl">
        <asp:ListItem Text="Text Box" Value="TextBox" Selected="True"></asp:ListItem>
        <asp:ListItem Text="Drop Down" Value="Drop Down"></asp:ListItem>
        <asp:ListItem Text="Button" Value="Button"></asp:ListItem>
    </asp:DropDownList>
    <asp:Button runat="server" ID="btnAdd" onclick="btnAdd_Click" Text="Add" />


<div>
    <asp:PlaceHolder runat="server" ID="plcMain">
    </asp:PlaceHolder>
</div>
</div>

 

The above is very basic asp.net code which you should already be able to understand if you are attempting to work with dynamic controls. Most of the tricky section is in the code behind.

 

The entire trick to be able to pull this off is coming up with your own data structure which will enable you to describe each of the controls as a class. For this example i have kept it very simple. All I need to know is what type of control is added to the web page. So I have the following class defined outside the webpage. As a further example a simple way to extend this may be to either read it from a database / configuration or some other method adding a Dictionary of options or using an abstract class forcing the implementing class to act as an object factory for the dynamic control type. It really depends on how much functionality is required for each case.

 

[Serializable]
public class MyStruct
{
    public string ControlType = null;
}

 

 

The rest of the code that exists in the page looks like the following and is explained later.

 

 

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        lblInfo.Text = "";
        AddControls();
    }

    protected void btnAdd_Click(object sender, EventArgs e)
    {
        MyStruct tmp = new MyStruct();
        tmp.ControlType = ddlControl.SelectedValue;
        lstControls.Add(tmp);
        AddControl(tmp);
    }

    private void AddControls()
    {
        for (int i = 0; i < lstControls.Count; i++)
            AddControl(lstControls[i]);
    }

    private void AddControl(MyStruct S)
    {
        switch (S.ControlType)
        {
            case "TextBox":
                TextBox txt = new TextBox();
                txt.Text = "Default Text";
                plcMain.Controls.Add(txt);
                break;
            case "Drop Down":
                DropDownList ddl = new DropDownList();
                ddl.Items.Add("Sample Item");
                plcMain.Controls.Add(ddl);
                break;
            case "Button":
                Button btn = new Button();
                btn.Text = "Button Text";
                btn.Click += new EventHandler(btn_Click);
                plcMain.Controls.Add(btn);
                break;
            default:
                throw (new Exception("Unknown Control Type"));
        }

        Literal lit = new Literal();
        lit.Text = "<br>";
        plcMain.Controls.Add(lit);

    }

    private void btn_Click(object sender, EventArgs e)
    {
        lblInfo.Text = "Dynamic Button Clicked";
    }

    private List<MyStruct> lstControls {
        get
        {
            if (ViewState["lstControls"] == null)
                ViewState["lstControls"] = new List<MyStruct>();
            return (List<MyStruct>) ViewState["lstControls"];
        }
    }
}

 

 

As you can see I used hte viewstate to list my descriptive structure to all the controls that are added. You could of course use a session or application variable or any other means that is capable of keeping the list of controls added for that individual web page. Though viewstate works very well with this because its going to be very specific to that page and the following postbacks that are going to happen.

 

You can probably see from the specific parts. One of the first things that is done on the page load is to add all the controls that are in the list to the placeholder. It is very important to make sure you have all the control's back on the page before the end of page load.

 

So the rest is actually stright forward. When we create a control we add it to the end of the list and create the control on the page at the same time. This is because the btnAdd_Click is run well after the page_load function. After this stage the page will be delivered back to the web browser. On the next post back the page load function will be the first thing that is going to be run so we add all the controls on the list to the page creating them as our structure describes.

 

Note: It is hard to remove the control once it is added. However you can simply describe them as hidden.

 

Note: In this example if you extend it you may want to watch the size that your viewstate will grow.

E-mail Kick it! DZone it! del.icio.us Permalink


Comments (2) -

4/26/2011 3:05:58 PM #

This is great!  Thanks for posting this.  Would be interested in knowing how to process these dynmaically added controls - let's say we add several text boxes, and want to then save their values to a db, or add validation. Is this possible?

Keith Canada |

3/7/2012 10:30:35 AM #

Thank you Very Much it was helpful

Abdelrhamn Egypt |

Pingbacks and trackbacks (2)+