Thursday, October 28, 2010

Rendering asp.net controls with dynamic ids

You have a legacy asp application with lots of html and server side code.

And you you have a loop in which you are trying to add server controls and you want their ids to be dynamically generated.

You want the mark up to look like the following.  Here for this blog post purposes I am using textbox.


<input name="0" type="text" id="0" />
 <br />
<
input name="1" type="text" id="1" />
 <br />
<
input name="2" type="text" id="2" />
 <br />
<
input name="3" type="text" id="3" />
 <br />
<
input name="4" type="text" id="4" />



You might intuitively try the following

<%  for (var i = 0 ; i <5; i++){ %>
 <asp:TextBox runat="server" id="<%# i %>" />
<% }
%>




But this results in to the following error

The ID property of a control can only be set using the ID attribute in the tag and a simple value. Example: <asp:Button runat="server" id="Button1" />

Workaround for this issue is as follows.

First the Markup.

<% for (var i = 0; i < 5; i++) {

AddTextBox(i);

} %>

Here we are adding 5 text boxes dynamically to the page in place.

This kind of code gets executed at the rendering stage of the page life cycle.  Trick is get the html out of the text box and just render in place.

And code for AddTextBox method


void AddTextBox(int i){


    var ctrl = new TextBox() { ID = i.ToString() };


    var sb = new StringBuilder();


    using (var sw = new StringWriter(sb)){


        using (var textWriter = new HtmlTextWriter(sw)){


            ctrl.RenderControl(textWriter);


        }


    }


    Response.Write(sb.ToString());


}





Here we are creating a new TextBox control and setting its id property dynamically.   And then using RenderControl method, we are populating the StringBuilder instance.  And then outputting the value to response stream.

This can easily be turned in to an extension method.  Then the usage looks like the following

<%= TextBox.ToHtml(id, val) %>