Posted by Sébastien Lachance with Comments (0)
Edit : This is an old post back from november 2008 on my old blog. Since I had this problem today, I though it would be a good idea to share it again with all my readers.
Going back to standard ASP.NET Web Forms was ridiculously hard. In the last months, I have been completely blown away by the limitless (almost) possibilities of the ASP.NET MVC framework and now I find myself struggling very hard to make a single dropdownlist works the way I wanted to. The scenario was simple, in the client page, I used the value supplied by the drowdown list item to make an AJAX query and display the incoming results somewhere else in the page. That should be very easy right? Well, no. You may not know this but the value attribute of the ASP.NET CheckBoxList's items is not rendered at all.
I know that there is multiple solutions to render it, but that's not the point. I can't find a single reason to not let the developer decide if he want to display it or not. I even heard on some forum (I did not test it myself) that you cannot add a custom attribute named "value" (you can add custom attributes to any controls that will be rendered in the final html) without it to be stripped by the ASP.NET WebForms engine.
Anyway, let's see the solution to this problem.
First of all, we need to create a custom control that will inherit from the System.Web.UI.WebControls.CheckBoxList and that will implement the System.Web.UI.WebControls.IRepeatInfoUser. We use the base class CheckBoxList as we want to reuse existing behavior without implementing it ourselves. As for the IRepeatInfoUser interface, we use it because we are implementing a control that has list items.
public class CheckBoxListFixed : CheckBoxList, IRepeatInfoUser { void IRepeatInfoUser.RenderItem(ListItemType itemType, int repeatIndex, RepeatInfo repeatInfo, HtmlTextWriter writer) { } }
Inside the RenderItem method we will use the HtmlTextWriter to output all the wanted html. So we want to create an input of type checkbox:
writer.WriteBeginTag("input"); writer.WriteAttribute("type", "checkbox"); writer.Write(">"); writer.Write(Items[repeatIndex].Text); writer.WriteEndTag("input");
This will render only basic checkboxes.
<table id="checkboxList" border="0"> <tr> <td><input type="checkbox">1</input></td> </tr> <tr> <td><input type="checkbox">2</input></td> </tr> <tr> <td><input type="checkbox">3</input></td> </tr> <tr> <td><input type="checkbox">4</input></td> </tr> <tr> <td><input type="checkbox">5</input></td> </tr> <table>
With no IDs or attributes. Let's add those to each checkbox.
writer.WriteBeginTag("input"); writer.WriteAttribute("type", "checkbox"); writer.WriteAttribute("name", UniqueID + this.IdSeparator + repeatIndex.ToString(NumberFormatInfo.InvariantInfo)); writer.WriteAttribute("id", ClientID + this.ClientIDSeparator + repeatIndex.ToString(NumberFormatInfo.InvariantInfo)); if (Items[repeatIndex].Selected) writer.WriteAttribute("checked", "checked"); System.Web.UI.AttributeCollection attrs = Items[repeatIndex].Attributes; foreach (string key in attrs.Keys) { writer.WriteAttribute(key, attrs[key]); } writer.Write(">"); writer.Write(Items[repeatIndex].Text); writer.WriteEndTag("input");
We have also added the "checked" to each checkbox. Now we are ready to insert the "missing" value attribute. Adding the following line will resolve the problem.
writer.WriteAttribute("value", Items[repeatIndex].Value);
Complete control code :
namespace yourNamespace { public class CheckBoxListFixed : CheckBoxList, IRepeatInfoUser { void IRepeatInfoUser.RenderItem(ListItemType itemType, int repeatIndex, RepeatInfo repeatInfo, HtmlTextWriter writer) { writer.WriteBeginTag("input"); writer.WriteAttribute("type", "checkbox"); writer.WriteAttribute("name", UniqueID + this.IdSeparator + repeatIndex.ToString(NumberFormatInfo.InvariantInfo)); writer.WriteAttribute("id", ClientID + this.ClientIDSeparator + repeatIndex.ToString(NumberFormatInfo.InvariantInfo)); writer.WriteAttribute("value", Items[repeatIndex].Value); if (Items[repeatIndex].Selected) writer.WriteAttribute("checked", "checked"); System.Web.UI.AttributeCollection attrs = Items[repeatIndex].Attributes; foreach (string key in attrs.Keys) { writer.WriteAttribute(key, attrs[key]); } writer.Write(">"); writer.Write(Items[repeatIndex].Text); writer.WriteEndTag("input"); } } }
And here is a bonus : How to use this control in my code?
Supposing the control isn't in another library and that you cannot add it to your toolbox, you can always use the Register directive inside your aspx file.
<%@ Register TagPrefix="yourPrefix" Namespace="yourNamespace" %>
Next, you can declare your control with the format
<tagprefix:CheckboxListFixed runat="server" id="yourID" />
Related posts