Click here to Skip to main content
15,867,686 members
Articles / Web Development / CSS

Converting ASP.NET Control Check Box List into Drop-Down Check Box List

Rate me:
Please Sign up or sign in to vote.
4.85/5 (36 votes)
1 Dec 2010CPOL3 min read 170.1K   52   57
How to create your own drop-down check box list control

Introduction

When a developer wants to display a list of items with the ability to select some of them, there are not many options available, actually it comes to only two:

  1. List box
  2. Check box list

Both have some disadvantages.

The list box control selection is just highlighting of a row, which is a visually weak type of selection, multiple selection is not intuitive and is not convenient for the end user.

Check box list has a strong visual selection type but takes a lot of space if the list is long enough.

It would be nice to use something like a drop-down list, but unfortunately the drop-down list control does not support multiple-item selection.

The combination of the drop-down list and check box list would be ideal for this purpose.

So when the time had come and the web portal that I developed required to have such selection list, I started to do my homework and look for a suitable solution on the Internet.

I found a few, but was not satisfied with the complexity and overall amount of code to implement them.

I also found a nice JQuery extension, but it was a pure client side solution and I had something else in mind.

I decided to develop my own server side control.

I realized that it would be JavaScript driven, because I want to implement the client side click event to open and close the drop-down list.

My JavaScript of choice would be JQuery, which is very popular nowadays.

I also realized that CSS will be involved to style this control the way I wanted.

So the entire solution will be:

  1. Server side control
  2. Reference to JQuery library
  3. CSS (either a file of just a style tag)
  4. One image (an arrow down)

Server Side Control

Obviously, this control will inherit from CheckBoxList control.

I added three public properties (Title, ImageURL, and OpenOnStart) and overrode the Render procedure.

For my convenience when rendering the control, I added the reference to JQuery library inside the Render procedure, but you can do it differently.

So this is the source:

C#
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace CodeProjectWeb
{
    public class CheckBoxListDropDown : CheckBoxList
    {
        //First row
        public string Title { get; set; }

        public string ImageURL { get; set; }

        //Expand or hide on start
        public bool OpenOnStart { get; set; }

        /// Display as a dropdown list
        protected override void Render(System.Web.UI.HtmlTextWriter writer)
        {
            //default css class
            if (string.IsNullOrEmpty(this.CssClass))
                this.CssClass = "ddlchklst";

            //first row division: 
            string divFirstRow = @"
            <div>
               {0} <img id=""{1}"" style=""float: right;"" src=""{2}"" />
            </div>";

            //unorder list:
            string ulTag = "<ul style=\"display:{1}\" id=\"{0}\" >";

            //check box:
            string chkbox = "<input id=\"{0}\" name=\"{1}\" 
			type=\"checkbox\" value=\"{2}\"{3} />";

            //title for check box:
            string label = "<label for=\"{0}\">{1}</label>";

            string jqueryToggleFunction = @" 
            <script type=""text/javascript"">
                $(document).ready(function () {{
                    $(""#{0}"").click(function () {{
                        $(""#{1}"").toggle(""fast"");

                    }}); 
                        $("".{2} li:even"").css(""background-color"", ""#efefef"")
                }}); 
            </script>";

            //rendering the control:

            // optionally you can place reference to jquery library here:
            writer.WriteLine("<script type='text/javascript' 
		src='http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js'>
		</script>");
            writer.WriteLine(string.Format("<div class=\"{0}\">", this.CssClass));
            writer.Write(string.Format(divFirstRow, this.Title + "  ", 
		base.ClientID + "_arrowDown", ImageURL));
            writer.WriteLine();
            writer.Indent++;
            writer.WriteLine(string.Format(ulTag, base.ClientID + "_ul", 
		OpenOnStart ? "block" : "none"));

            for (int index = 0; index < Items.Count; index++)
            {
                writer.Indent++;
                writer.WriteLine("<li>");
                writer.Indent++;

                writer.WriteLine(string.Format(chkbox,
                    base.ClientID + "_" + index.ToString(),
                    base.ClientID + "$" + index.ToString(),
                    Items[index].Value,
                    (Items[index].Selected ? " checked" : " ")));

                writer.WriteLine(string.Format(label, 
		base.ClientID + "_" + index.ToString(), Items[index].Text + " "));
                writer.Indent--;

                writer.WriteLine("</li>");
                writer.WriteLine();
                writer.Indent--;
            }
            writer.WriteLine("</ul>");
            writer.WriteLine("</div>");
            writer.Write(string.Format(jqueryToggleFunction, 
		base.ClientID + "_arrowDown", base.ClientID + "_ul", this.CssClass));
        }
    }
}

Testing the Control

ASPX Page

XML
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="DropdownCheckcs.aspx.cs"
    Inherits="CodeProjectWeb.DropdownCheckcs" %>

<%@ Register Assembly="CodeProjectWeb" Namespace="CodeProjectWeb" TagPrefix="cc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <style type="text/css">
        .ddlchklst
        {
            width: 170px;
            border:solid 1px silver;
        }
        .ddlchklst ul
        {
          margin:0;
          padding:0;
           border-top:solid 1px silver;
            }
        .ddlchklst li
        {
            list-style: none;
        }
    </style>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <cc1:CheckBoxListDropDown ID="ddlchklst"  runat="server" 
	Title="Select what you need" OpenOnStart="true" ImageURL="/images/DropDown.PNG">
        </cc1:CheckBoxListDropDown>
    </div>
    <div>
        <asp:Button ID="btn" runat="server" Text="Save" OnClick="btn_Click" />
    </div>
    </form>
</body>
</html>

Please note that you have to register the control:

ASP.NET
<%@ Register Assembly="CodeProjectWeb" Namespace="CodeProjectWeb" TagPrefix="cc1" %>

User your own Assembly and Namespace to register.

Use the following image to display the down arrow: DropDown.PNG Place this image into a convenient location and set the ImageURL property correctly.

Also this is our CSS:

CSS
<style type="text/css">
        .ddlchklst
        {
            width: 170px;
            border:solid 1px silver;
        }
        .ddlchklst ul
        {
          margin:0;
          padding:0;
           border-top:solid 1px silver;
            }
        .ddlchklst li
        {
            list-style: none;
        }
    </style>

ASPX.cs

C#
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace CodeProjectWeb
{
    public partial class DropdownCheckcs : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                string[] ds = new string[] { "one", "two", "three", 

		"four", "five", "six", "seven", "eight", "nine", "ten" };
                this.ddlchklst.DataSource = ds;
                this.ddlchklst.DataBind();
            }
        }

        protected void btn_Click(object sender, EventArgs e)
        {

            foreach (ListItem li in this.ddlchklst.Items)
           {
               Response.Write( li.Value +": " +li.Selected.ToString() + "
");
           }

        }
    }
}

Result

This is the result you will see when you expand the list:

DDL.png

Updated Version of the Control

Added on December 1st, 2010

Having some positive feedback I decided to improve the control, making sure that it really inherits from the CheckBoxList control. The new version has implemented the following list of properties:

  1. AutoPostBack
  2. BackColor
  3. BorderColor
  4. BorderStyle
  5. BorderWidth
  6. Font-Bold
  7. etc...

And, as you see from the list of the properties, I do not need a CSS class anymore.
You can get everything by using the formatting properties.

There are still a couple of issues, but it would be unfair for other developers to rob them on the ability to improve somebody's work. :-)

Some properties I decided not to inherit, I don't think it would be useful (CellPadding, CellSpacing, etc.).

Here is the code:

C#
public class DropDownCheckBoxList : CheckBoxList
    {
        //First row
        public string Title { get; set; }

        //Arrow Down
        public string ImageURL { get; set; }

        //JQuery base library
        public string JQueryURL { get; set; }

        //Expand or hide on start
        public bool OpenOnStart { get; set; }

        //alternative row color:
        public Color AltRowColor { get; set; }

        protected override void OnLoad(EventArgs e)
        {
            if (string.IsNullOrEmpty(ImageURL))
                throw new Exception("ImageURL was not set.");

            if (string.IsNullOrEmpty(JQueryURL))
                throw new Exception("JqueryURL was not set.");

            base.OnLoad(e);
        }

        /// Display as a dropdown lis
        protected override void Render(System.Web.UI.HtmlTextWriter writer)
        {
            //catch ForeColor:
            if (this.ForeColor.IsEmpty)
                this.ForeColor = Color.Black;

            //catch AltRowColor:
            if (this.AltRowColor.IsEmpty)
                this.AltRowColor = Color.GhostWhite;

            //catch border style:
            if (this.BorderStyle.Equals(BorderStyle.NotSet) ||
                 this.BorderStyle.Equals(BorderStyle.NotSet))
                this.BorderStyle = BorderStyle.Solid;

            //catch border color:
            if (this.BorderColor.IsEmpty)
                this.BorderColor = Color.Silver;

            //catch border width:
            if (this.BorderWidth.IsEmpty)
                this.BorderWidth = Unit.Pixel(1);

            //catch background width:
            if (this.BackColor.IsEmpty)
                this.BackColor = Color.White;

            StringBuilder sbCss = new StringBuilder();

            //css definition
            sbCss.Append("<style type=\"text/css\">");
            sbCss.Append(".{0}{{");
            if (this.Font.Italic)
                sbCss.Append("font-style:italic; ");
            if (this.Font.Bold)
                sbCss.Append("font-weight:bold; ");

            string textDecor = string.Empty;
            if (Font.Overline || Font.Underline || Font.Strikeout)
            {
                sbCss.Append("text-decoration:");
                if (this.Font.Overline)
                    sbCss.Append("overline ");
                if (this.Font.Strikeout)
                    sbCss.Append("line-through ");
                if (this.Font.Underline)
                    sbCss.Append("underline ");
                sbCss.Append("; ");
            }
            if (!ForeColor.IsEmpty)
                sbCss.Append("color:" + ForeColor.Name.Replace("ff", "#") + "; ");
            if (!Font.Size.IsEmpty)
                sbCss.Append("font-size:" + Font.Size + "; ");
            if (!BackColor.IsEmpty)
                sbCss.Append("background-color: " + 
		BackColor.Name.Replace("ff", "#") + "; ");
            sbCss.Append("width: {1}; ");
            sbCss.Append(" border:" + BorderStyle + " " + 
		BorderWidth + " " + this.BorderColor.Name.Replace
		("ff", "#") + "; }}.{0} ul  {{overflow:auto; height:{2}; 
		margin:0;  padding:0; border-top:solid 1px " + 
		BorderColor.Name.Replace("ff", "#") + "; ");

            sbCss.Append("}} .{0} li {{list-style: none;}}</style>");

            string css = sbCss.ToString();

            //default css class
            if (string.IsNullOrEmpty(this.CssClass)) this.CssClass = "ddlchklst";

            //default width and height:
            if (Width.IsEmpty) Width = Unit.Pixel(170);
            if (Height.IsEmpty) Height = Unit.Pixel(170);

            //first row division: 
            string divFirstRow = @"<div>   {0} <img id=""{1}"" 
			style=""float: right;"" src=""{2}"" /> </div>";

            //unorder list:
            string ulTag = "<ul style=\"display:{1}\" id=\"{0}\" >";

            //check box:
            string chkBox = "<input id=\"{0}\" name=\"{1}\" 
			type=\"checkbox\" value=\"{2}\"{3}{4}{5} />";

            //attributes to render:
            string attrs = string.Empty;
            foreach (string key in this.Attributes.Keys)
            {
                attrs += " " + key + "=" + "\"" + this.Attributes[key].ToString() + "\"";
            }

            //title for check box:
            string label = "<label for=\"{0}\">{1}</label>";

            //toggle click
            string jqueryToggleFunction = @"<script type=""text/javascript"">  
		$(document).ready(function () {{   $(""#{0}"").click(function () 
		{{ $(""#{1}"").toggle(""fast"");  }});   
		$("".{2} li:even"").css(""background-color"", """ + 
		AltRowColor.Name.Replace("ff", "#") + "\") }});  </script>";

            //*************  rendering  ***********************//

            //render css:
            writer.WriteLine(string.Format(css, CssClass, Width, Height));

            //render jquery url:
            writer.WriteLine(string.Format("<script type='text/javascript' 
		src='{0}'></script>", JQueryURL));

            //render toggle click function:
            writer.Write(string.Format(jqueryToggleFunction, base.ClientID + 
		"_arrowDown", base.ClientID + "_ul", this.CssClass));

            //render the div start tag:
            writer.WriteLine(string.Format("<div class=\"{0}\">", this.CssClass));

            //render first row with the title:
            writer.Write(string.Format(divFirstRow, this.Title + "  ", 
		base.ClientID + "_arrowDown", ImageURL));
            writer.WriteLine();
            writer.Indent++;

            //render ul start tag:
            writer.WriteLine(string.Format(ulTag, base.ClientID + "_ul", 
			OpenOnStart ? "block" : "none"));

            //render the check box list itself:
            for (int index = 0; index < Items.Count; index++)
            {
                writer.Indent++;
                writer.WriteLine("<li>");
                writer.Indent++;
                writer.WriteLine(string.Format(chkBox,
                    base.ClientID + "_" + index.ToString(),
                    base.ClientID + "$" + index.ToString(),
                    Items[index].Value,
                    (Items[index].Selected ? " checked=true" : " "),
                    (AutoPostBack ? " onclick=\"" + HttpUtility.HtmlEncode
		  ("javascript:setTimeout('__doPostBack(<a href="file://'/">\\'</a>" + base.ClientID + "$" 
		  + index.ToString() + "\\',\\'\\')', 0)") + "\"" : ""),
                    attrs
                    ));
                writer.WriteLine(string.Format(label, base.ClientID + "_" + 
		index.ToString(), Items[index].Text + " "));
                writer.Indent--;

                writer.WriteLine("</li>");
                writer.WriteLine();
                writer.Indent--;
            }

            //render end ul tag:
            writer.WriteLine("</ul>");

            //render end div tag:
            writer.WriteLine("</div>");
        }
    }

New Implementation

Now you don't need to supply the CSS class, but you must specify the "arrow down" image and reference to the JQuery library:

XML
<cc1:DropDownCheckBoxList ID="DropDownCheckBoxList1" runat="server" 
	Title="Select..." ImageURL="/images/dropdown.png" 
	JQueryURL="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js">
</cc1:DropDownCheckBoxList>

Pretty easy, isn't it? Good luck in implementing.

Conclusion

As you can see, this control is easy to implement and you can change the way it looks by changing the Render procedure and/or CSS class.

If you like this article, please vote for it. It is important because it allows more programmers to utilize this code.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
United States United States
I started as an electronic engineer and moved into programming in 1989, was fascinated by Internet and developed my first web application in 1997.
When Microsoft introduced C# I became its fan and am not disappointed by now.
As for the hobbies, except of course reading, I love skiing and horse riding.

Comments and Discussions

 
GeneralThanks a Lot. Pin
rmcomics21-Feb-11 1:07
rmcomics21-Feb-11 1:07 
GeneralRe: Thanks a Lot. Pin
Ed Guzman21-Feb-11 4:15
Ed Guzman21-Feb-11 4:15 
GeneralRe: Thanks a Lot. Pin
rmcomics21-Feb-11 8:59
rmcomics21-Feb-11 8:59 
GeneralRe: Thanks a Lot. Pin
rmcomics21-Feb-11 10:10
rmcomics21-Feb-11 10:10 
GeneralMy vote of 5 Pin
Ali Al Omairi(Abu AlHassan)13-Feb-11 13:13
professionalAli Al Omairi(Abu AlHassan)13-Feb-11 13:13 
GeneralRe: My vote of 5 Pin
Ed Guzman14-Feb-11 5:32
Ed Guzman14-Feb-11 5:32 
GeneralSelected Index changed... Pin
dexters00711-Jan-11 2:04
professionaldexters00711-Jan-11 2:04 
GeneralRe: Selected Index changed... Pin
Ed Guzman11-Jan-11 3:23
Ed Guzman11-Jan-11 3:23 
This control has whatever the regular check box list has. If you want to implement some functionality on auto post-back you have to write some code according to your logic. Sorry, this is just a control Smile | :)
Questionli.selected always false Pin
Vomisa1-Jan-11 3:38
Vomisa1-Jan-11 3:38 
AnswerRe: li.selected always false Pin
Ed Guzman1-Jan-11 6:35
Ed Guzman1-Jan-11 6:35 
GeneralRe: li.selected always false Pin
Vomisa1-Jan-11 7:27
Vomisa1-Jan-11 7:27 
GeneralRe: li.selected always false Pin
BaldPaddy10-Mar-11 7:09
BaldPaddy10-Mar-11 7:09 
GeneralRe: li.selected always false Pin
kgorrepati10-May-11 9:52
kgorrepati10-May-11 9:52 
GeneralExcellent article addressing rather important issue w/data control Pin
DrABELL14-Dec-10 17:30
DrABELL14-Dec-10 17:30 
GeneralRe: Excellent article addressing rather important issue w/data control Pin
Ed Guzman15-Dec-10 1:42
Ed Guzman15-Dec-10 1:42 
GeneralMy vote of 4 Pin
Pranay Rana6-Dec-10 21:25
professionalPranay Rana6-Dec-10 21:25 
GeneralRegarding code Pin
Tridip Bhattacharjee5-Dec-10 5:01
professionalTridip Bhattacharjee5-Dec-10 5:01 
GeneralGood work... Pin
Sandeep Mewara1-Dec-10 5:16
mveSandeep Mewara1-Dec-10 5:16 
GeneralRe: Good work... Pin
Ed Guzman1-Dec-10 5:51
Ed Guzman1-Dec-10 5:51 
GeneralRe: Good work... Pin
Sandeep Mewara1-Dec-10 5:54
mveSandeep Mewara1-Dec-10 5:54 
QuestionAutopostback=true Pin
Sunasara Imdadhusen1-Dec-10 0:08
professionalSunasara Imdadhusen1-Dec-10 0:08 
AnswerRe: Autopostback=true Pin
Ed Guzman1-Dec-10 0:33
Ed Guzman1-Dec-10 0:33 
GeneralRe: Autopostback=true Pin
Sunasara Imdadhusen1-Dec-10 1:05
professionalSunasara Imdadhusen1-Dec-10 1:05 
GeneralRe: Autopostback=true Pin
Ed Guzman1-Dec-10 10:28
Ed Guzman1-Dec-10 10:28 
GeneralMy vote of 5 Pin
Sunasara Imdadhusen1-Dec-10 0:06
professionalSunasara Imdadhusen1-Dec-10 0:06 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.