ASP.NET: Alternatives to Dynamic Controls – Part 1

This is part 1 of what I intend to be something of a recurring theme: how to avoid the use of dynamic controls in ASP.NET.

Whilst dynamic controls have their uses in a small number of cases, they come with a significant amount of extra baggage. For example:

    * Dynamic controls need to be created early in the page lifecycle to participate in viewstate     * Dynamic controls need to be re-created on each postback, and assigned the same control IDs to maintain viewstate     * Extracting values from dynamic controls on postback is not straightforward.

There are of course workarounds to all of the above obstacles- but the fact remains, if a built-in ASP.NET control does, or can be coerced into doing, what you need, then the simpler approach should prevail.

I’m often surprised by the number of times I see some code like this:

private
void CreateTextBoxes(int count) {
 TextBox tb = null;
 for (int i = 0; i < count; i++) {
 tb = new TextBox;
 tb.ID = "txt" + i.ToString;
 this.Panel1.Controls.Add(tb);
 }
}

To dynamically create textboxes. When asked why they are using dynamic controls, the coder will often reply ‘because I don’t know how many textboxes I need until runtime’. This is, of course, a valid concern, but in this case, dynamic controls are usually not a good solution when a Repeater, DataList, or ListView control can be employed to the same effect, with much less effort.

For example, let’s take the case of a page which initially loads with a single textbox, but contains a button which allows the user to add additional textboxes at runtime. To show how much easier the solution is using built-in.NET controls, I started by adding a ListView control to the page, and edited its ItemTemplate and LayoutTemplate like so:

<asp:ListView ID="lvDynamicTextboxes" runat="server"
 ItemPlaceholderID="itemPlaceholder"> <LayoutTemplate> <table> <asp:PlaceHolder ID="itemPlaceholder"
 runat="server"></asp:PlaceHolder> </table> </LayoutTemplate> <ItemTemplate> <tr> <asp:TextBox ID="txtText" runat="server"> </asp:TextBox> </tr> </ItemTemplate>
</asp:ListView>
Next up, I added a button to the page, which will be used to add new textboxes:

<asp:Button ID="btnAddTextBox" runat="server"
 Text="Add" onclick="btnAddTextBox_Click" />
I then created two methods- one for binding the ListView, and one for incrementing the current textbox count, which I chose to store using ViewState:

private void BindListView
{
 //get the current textbox count int count = 1;
 if (ViewState["textboxCount"]!= null)
 count = (int)ViewState["textboxCount"];

 //create an enumerable range based on the current count IEnumerable<int> enumerable = Enumerable.Range(1, count);

 //bind the listview this.lvDynamicTextboxes.DataSource = enumerable;
 this.lvDynamicTextboxes.DataBind;
}

private void IncrementTextboxCount
{
 int count = 1;
 if (ViewState["textboxCount"]!= null)
 count = (int)ViewState["textboxCount"];

 count++;
 ViewState["textboxCount"] = count;
}

You will notice in the above that I’m using the Enumerable.Range method which is located within the System.Linq namespace in the.NET framework 3.0 and greater. This is used to automatically create an integer collection with a specified range: a quick and easy way of generating a datasource for these purposes.

The only thing left to do now, is bind the ListView in the page load, and increment the TextBox count and rebind when the button is clicked:

protected
void Page_Load(object sender, EventArgs e) {
 if (!Page.IsPostBack) {
 this.BindListView;
 }
}

protected
void btnAddTextBox_Click(object sender, EventArgs e) {
 this.IncrementTextboxCount;
 this.BindListView;
}

“But… hang on a minute”, you might well say, “that’s actually more code than I needed before, using dynamic controls”.

Well, yes, it is. But the real gains come when you need to extract the values from the textboxes you have dynamically created. Using dynamic controls, this gets very ugly very quickly. Using a ListView, you need only to iterate through the ListView’s data items, and extract the textbox values from the data rows, like so:

private IList<string> GetValues
{
 List<string> values = new List<string>;
 TextBox txt = null;
 foreach (ListViewItem item in this.lvDynamicTextboxes.Items)
 {
 if (item is ListViewDataItem)
 {
 txt = (TextBox)item.FindControl("txtText");
 values.Add(txt.Text);
 }
 }
 return values;
}

And that’s all there is to it.

For preserving the values of the textboxes between postbacks, see part 2.

This article is part of the GWB Archives. Original Author: gwbarchive

New on Geeks with Blogs

  • We Won The One Award I Actually Care About

    Full Scale made the Inc. 5000 for the fifth year straight, the 12th listing across my three companies. Here is why the one award you cannot buy is worth stopping for.

  • Your Customers Build the Features Now

    I let a tool I liked sit dead for a year rather than build the features I wanted. An MCP server meant I never had to, and your customers can do the same to your product.

  • Get the Size of a Directory in Linux the Easy Way

    du -sh for the quick answer, ncdu for the cleanup, df for the disk itself: every command for checking directory size in Linux, plus why du and df never agree.

  • Vim Search and Replace: The Ultimate Guide

    One :%s command replaces every match in a file before a find dialog would even open. The Vim substitute patterns worth the muscle memory: flags, ranges, capture groups, and multi-file edits.