Creating ASP.NET controls dynamically at runtime

Posted by Adrian O'Connor Wed, 18 Apr 2007 13:00:00 GMT

Being able to create controls dynamically is a powerful feature when used well. It is how you allow for the unlimited customisation of pages and forms, and is a corner stone of many ‘shrink-wrapped’ application. For example, your users might configure a form that is particular to their company. You would store this configuration in the database and then build the form dynamically each time it was required, based on the configuration.

Prior to ASP.NET 2.0, you had to jump through certain hoops to get your controls ready in time for the event handlers. This usually meant overloading the LoadViewState method, and being mindful of certain other constraints. Luckily, Microsoft seem to have made changes, and dynamic control creation is now very easy.

Your should use PlaceHolders or Panels to house your controls. For example,

<asp:PlaceHolder ID="MyPlaceHolder" Runat="Server" />

In your Page_Load method, you create the controls and Add them to the panel. The controls can maintain their state only if their ID identical each time the page runs. If you have hard-coded your controls, there is no problem:

protected void Page_Load(object sender, EventArgs e)
{
  TextBox t = new TextBox();
  t.ID = "MyLovelyTextBox";

  MyPlaceHolder.Controls.Add(t);
}

The ID will always be the same, and if you have any events on your page (e.g. as the result of a Button’s OnClick) they will be able to access the contents of the TextBox. To do this, you need to find the control and then cast it to it’s correct type:

protected void MyButton_OnClick(object sender, EventArgs e)
{
  Control c = FindControl("MyLovelyTextBox");

  string Result = ((TextBox)c).Text;
}

You could of course cast the result of FindControl, if you always know the type before hand:

TextBox t = (TextBox)FindControl("MyLovelyTextBox");

Things are a little tricker if you need to add/remove fields based on a changing configuration or based on what the user is doing (for example, a booking form might add a new text field for each person in a group). The best way to do this is to keep track of your controls using a Stack, stored in the page’s ViewState. Each time you add a new field, you .Push() it on to the stack. In your Page_Load method, you can create a copy of the Stack and the .Pop() all of the controls, creating them as you go. I say you should make a copy because once you Pop all of the items off the stack, they disappear forever and all of your controls would disappear on the next PostBack event.

You will probably find that this is most useful when used in combination with WebControls, rather than simple controls like the TextBox. Luckily, it is really easy to dynamically create WebUserControls at runtime:

Control person_details = LoadControl("~/GroupBookings/PersonDetailElement.ascx")
person_details.ID = "Person_" + NumberOfPeople.ToString();
PartyPeople.Controls.Add(person_details);

Any fields and postback events in your WebUserControl will fire correctly, just as if you’d added them in the designed, as long as you remember to set the ID property (and it is unique), and you create it on each Page_Load.

Before closing, I shall leave you with one word of warning. While dynamic control creation is a wonderful thing when writing extensible applications, it can be easily abused. If there is an easier option using controls placed directly on the form, you will probably be better off taking that.

Comments

Leave a response

Comments