
Introduction
The TitleCheckBoxList control is designed to allow you to insert column headers / titles into a CheckBoxList. The titles are included in the Items collection of the ListControl, but do not render a CheckBox on the form.
This control is useful if you have a number of options that you want to display in a list of checkboxes and you want to group and organize the checkboxes according to the type or category of the option it represents.
Using the Control
Step 1: Add the TitleCheckBoxList.cs class file to your project in the App_Code folder.
You can download this C# class file by clicking the 'Download source code' link at the top of this article.
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.IO;
namespace VwdCms
{
public class TitleCheckBoxList : CheckBoxList
{
public const string TitleValue = "###title###";
public const string SpacerValue = "###spacer###";
private Unit _titleWidth;
public Unit TitleWidth
{
get { return _titleWidth; }
set { _titleWidth = value; }
}
protected override void RenderItem(ListItemType itemType,
int repeatIndex, RepeatInfo repeatInfo, HtmlTextWriter writer)
{
ListItem itm = this.Items[repeatIndex];
string val = itm.Value;
if (val == TitleValue || val == SpacerValue )
{
if (repeatIndex == 0)
{
StringWriter sw = new StringWriter();
HtmlTextWriter dummyWriter = new HtmlTextWriter(sw);
base.RenderItem(itemType, repeatIndex,
repeatInfo, dummyWriter);
}
if (val == TitleValue)
{
Label lbl = new Label();
lbl.Font.CopyFrom(this.Font);
lbl.Font.Bold = true;
lbl.Text = itm.Text;
if (this.TitleWidth != null)
{
lbl.Width = this.TitleWidth;
}
lbl.RenderControl(writer);
}
else if (val == SpacerValue)
{
writer.Write(HtmlTextWriter.SpaceChar);
}
}
else
{
base.RenderItem(itemType, repeatIndex, repeatInfo, writer);
}
}
}
}
Step 2: Update your web.config file's Controls section (inside the system.web section):
<pages>
<controls>
<add tagPrefix="VwdCms" namespace="VwdCms"/>
</controls>
</pages>
Step 3: Add a TitleCheckBoxList control to your Web Form:
<VwdCms:TitleCheckBoxList runat="server" ID="cblTitles"
RepeatDirection="Vertical" RepeatColumns="5"
style="font-family:Arial;font-size:8pt;text-align:left;
border:solid 1px #336699;" TitleWidth="90px" />
Some Examples
You can download the code for these examples by clicking the 'Download demo' link at the top of this article.
Example 1
This example demonstrates how the TitleCheckBoxList will render when all of the columns have the same number of items.
Since we know in advance in this example that we will have five different "Categories" (Titles), we can set the RepeatColumns property of the CheckBoxList to 5 and we get a clean looking display of 5 columns with an equal number of CheckBoxes.
By setting the TitleWidth property of TitleCheckBoxList, we can get the spacing between the columns without having to work with the RepeatLayout of the CheckBoxList.

Here is the code to load this TitleCheckBoxList:
if (!this.Page.IsPostBack)
{
int catNum = 0;
int itmNum = 0;
int i = 0;
ListItem itm = null;
for (catNum = 0; catNum < 5; catNum++)
{
itm = new ListItem("Category " + catNum.ToString(),
VwdCms.TitleCheckBoxList.TitleValue);
this.cblTitles.Items.Add(itm);
itmNum++;
for (i = 0; i < 6; i++)
{
itm = new ListItem("Item " + itmNum.ToString(),
itmNum.ToString());
itm.Selected = (itmNum % 2 == 0);
this.cblTitles.Items.Add(itm);
itmNum++;
}
}
}
Example 2
This example demonstrates how the TitleCheckBoxList will render when the number of items in each category is different.
For some applications, this might be acceptable; for others, it may be necessary to make the display a little bit cleaner. See Example 3 to see how to clean up the display.

Here is the code to load this TitleCheckBoxList:
if (!this.Page.IsPostBack)
{
int catNum = 0;
int itmNum = 0;
int i = 0;
int itemCount = 6;
ListItem itm = null;
for (catNum = 0; catNum < 5; catNum++)
{
itm = new ListItem("Category " + catNum.ToString(),
VwdCms.TitleCheckBoxList.TitleValue);
this.cblTitles.Items.Add(itm);
itmNum++;
for (i = 0; i < itemCount; i++)
{
itm = new ListItem("Item " + itmNum.ToString(),
itmNum.ToString());
itm.Selected = (itmNum % 2 == 0);
this.cblTitles.Items.Add(itm);
itmNum++;
}
itemCount--;
}
}
Example 3
This example demonstrates how the TitleCheckBoxList will render when the number of items in each category is different, but we can get a clean column display by adding "spacer" ListItems.

Here is the code to load this TitleCheckBoxList:
if (!this.Page.IsPostBack)
{
int catNum = 0;
int itmNum = 0;
int i = 0;
int itemCount = 6;
int itemCountMax = 6;
ListItem itm = null;
for (catNum = 0; catNum < 5; catNum++)
{
itm = new ListItem("Category " + catNum.ToString(),
VwdCms.TitleCheckBoxList.TitleValue);
this.cblTitles.Items.Add(itm);
itmNum++;
for (i = 0; i < itemCountMax; i++)
{
if (i > itemCount - 1)
{
itm = new ListItem(string.Empty,
VwdCms.TitleCheckBoxList.SpacerValue);
}
else
{
itm = new ListItem("Item " + itmNum.ToString(),
itmNum.ToString());
itm.Selected = (itmNum % 2 == 0);
}
this.cblTitles.Items.Add(itm);
itmNum++;
}
itemCount--;
}
}
Handling Postbacks
There is a slight difference during postBack processing that you will need to keep in mind when using the TitleCheckBoxList. The underlying CheckBoxList thinks that all of the ListItems in the Items collection are valid CheckBox controls. In fact, they are valid ListItems, but the TitleCheckBoxList's RenderItem method prevents the CheckBox control from being rendered for the title and spacer items.
The result is that your code will need to check for titles and spacers as you iterate through the Items collection to determine which items are checked and not checked.
Here is some example code:
void btnPostback_Command(object sender, CommandEventArgs e)
{
StringBuilder sbSelected = new StringBuilder();
StringBuilder sbNonSelected = new StringBuilder();
foreach (ListItem itm in this.cblTitles.Items)
{
if (itm.Value != VwdCms.TitleCheckBoxList.TitleValue
&& itm.Value != VwdCms.TitleCheckBoxList.SpacerValue )
{
if (itm.Selected)
{
sbSelected.Append(itm.Text);
sbSelected.Append(", ");
}
else
{
sbNonSelected.Append(itm.Text);
sbNonSelected.Append(", ");
}
}
}
this.lblSelected.Text = sbSelected.ToString();
this.lblNonSelected.Text = sbNonSelected.ToString();
}
Points of Interest
What the heck is dummyWriter doing in the RenderItem method of TitleCheckBoxList?
I ran into a strange problem when I tried out the overridden RenderItem method - all of the checkboxes in the TitleCheckBoxList were disabled. When I tried it without any title ListItems, the checkboxes were enabled. After a few minutes of experimentation, I figured out that it only happens when the first ListItem is a title. Apparently, the RenderItem method of the base class, CheckBoxList, is doing something when the first ListItem is rendered, and if you don't use the RenderItem of the base class for that first ListItem, all of the checkboxes will be disabled.
I looked at the CheckBoxList class documentation and could not find any way to control this behavior. So, the bottom line is that I need to call the CheckBoxList's RenderItem method on the first ListItem, despite the fact that I really don't want to use it. What I want is to occasionally override the behavior to render titles, but otherwise use the base class implementation for rendering checkboxes. In my opinion, this issue is a bug in the CheckBoxList class since you should not be forced to use the base method if the class is truly virtual. I haven't bothered to report this to Microsoft - feel free to let them know about it!
The simplest solution that I could think of was to execute the base class' RenderItem method, but don't let it output any HTML to the Web Form. This is where the dummyWriter comes in to play; the base class does its work on the first ListItem and outputs HTML to the dummyWriter which never gets used for anything.
Taking it Further...
Rendering horizontally
For the moment, the TitleCheckBoxList is doing exactly what I need, so I have not added any other feature or tried any other variations on the output. Your needs will certainly vary, and you should feel free to experiment with it even further. Maybe you will want to render the checkboxes in rows rather than columns, this doesn't seem like it would be too difficult to accomplish. I would approach it by setting the RepeatDirection to "Horizontal" and then setting the RepeatColumns property to the maximum number of ListItems that you want displayed on a row. There might be some tricky code when you load the TitleCheckBoxList so that you insert spacers and the row titles in the correct spots, but it should be possible.
Inserting other controls or content into a CheckBoxList
Is there any reason why we can't insert other types of controls into the CheckBoxList? I needed to get a title into the CheckBoxList, but maybe you want to insert a Button or an Image. Can this be done? Absolutely! If you follow the example of how to render a Label control in the TitleCheckBoxList's RenderItem method, you can basically render any kind of control in place of a ListItem.
Conclusion
The .NET Framework and ASP.NET makes it really easy to modify and extend the functionality of the classes and controls. All you need is a little bit of knowledge of how the framework is built and how the components interact with each other.
By extending the CheckBoxList class with less than 70 lines of code, I was able to get the exact functionality that I was looking for. So, if the built-in controls are not doing what you want, don't give up on them, change the way they work to suit your needs better!