It's one year later. I've gained some architectural insight, and to those who've been critical of this approach, I see your point. That said, the code here does work properly - it's just highly inelegant.
ASP.NET server controls are designed to allow for event-driven programming and stateful behavior in the inherently stateless environment of the web. This is a good thing as it frees the programmer from having to parse Forms and QueryStrings and instead allows the developer to address visual elements on the page (i.e. text fields, drop down lists, labels, etc.) the same way you would deal with elements in a desktop application. The result is a huge savings of time, a nearly complete separation of UI and code, and an application that is far easier to debug.
Unfortunately, many of these controls are buggy and/or have missing features. Most notably, the
A common scenario in web development involves a list of checkboxes next to a bunch of items in a form. After submission of the form, the checked items are dealt with in some way (i.e. multiple deletion of messages in Hotmail.) Due to limitations in the
CheckBox server control and a lack of documentation surrounding the proper use of
Repeaters, developers have historically dealt with this problem by using a client side
The problem is fundamentally this: server side
CheckBox controls lack a "
Value" attribute. Therefore, it is difficult to use them with dynamically generated lists of data in a
Repeater, as there is no straightforward way to determine which
checkboxes represent which data item after the form is posted back.
There have been many solutions posted on the web which involve re-evaluating each data item in the repeater after PostBack using a looping approach. This method is error prone (such as with forward only readers) as well as being inefficient. The method I present here instead retrieves the data only once, stores it in a hidden server control paired with the
checkbox, and allows for quick and easy retrieval on PostBack.
The following snippets show a typical example where a customer list is displayed, with a
checkbox next to each customer. After the user clicks a button, messages are sent only to the customers who they have checked off.
The Front-End Code
<asp:Repeater id="customerList" runat="server">
<%# Eval("name") %><br />
<%# Eval("email") %><br />
Send mailing list invite <asp:CheckBox id="selectUser" runat="server">
<asp:HiddenField ID="hiddenEmail" Value ='<%#Eval("email")%>'>
<asp:Button Text="Send Message" OnClick="DoSend" Runat="server" />
What we have done here is place an invisible server control, the
asp:HiddenField, inside the
Repeater template. Since this control DOES allow a value to be assigned to it, we can now determine which
checkbox is linked to which row.
To retrieve the email addresses associated with the checked items after PostBack, we need only to use a simple loop, as follows:
public void DoSend(object sender, EventArgs e)
foreach (RepeaterItem i in customerList.Items)
CheckBox cb = (CheckBox)i.FindControl("selectUser");
HiddenField hiddenEmail = (HiddenField)i.FindControl("hiddenEmail");
And that's all, folks! May the "I want to bang my head against the wall because I can't use a
checkbox insider a
repeater" phenomenon be but a distant memory.
Points of Interest
Microsoft has put a lot of work into its
GridView control (for example, this particular problem is not an issue there) but really neglected its
Repeater, which hasn't even changed significantly since ASP.NET 2.0.
Many coders choose the
GridView over the
Repeater partly for this reason.
Repeaters are far more lightweight, and allow for full control over what is rendered. Hopefully this workaround will help to encourage its use.