Click here to Skip to main content
Click here to Skip to main content

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

, 1 Dec 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
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:

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

<%@ 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:

<%@ 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:

<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

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. Smile | :)

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

Here is the code:

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:

<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)

Share

About the Author

Ed Guzman
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

 
Questionli.selected always false in master page PinmemberMember 1030794330-Sep-13 19:42 
QuestionHow to Enable False in this control Pinmembermominshiraj26-Aug-13 3:42 
GeneralMy vote of 5 PinprofessionalAntariksh Verma24-Jul-13 2:56 
QuestionScrollbars? Pinmemberpeter_x12-Jul-13 7:37 
GeneralMy vote of 5 PinmemberSandeep Prajapati11-Jul-13 3:12 
SuggestionExtender PinmemberHossein Montazeri19-Jun-13 6:21 
Suggestioncss Pinmembercassio vargas carrapatos28-Feb-13 18:35 
GeneralMy vote of 5 Pinmemberzakir shah6-Jan-13 20:34 
QuestionI need help Pinmemberdinesh_6-Dec-12 23:37 
QuestionVery Useful - Qn on Select/Unselect All PinmemberSundar Rajrathnam10-Sep-12 3:02 
QuestionPage Postback In update panel breaks control PinmemberCourt B12-Jan-12 8:22 
AnswerRe: Page Postback In update panel breaks control PinmemberEd Guzman23-Jan-12 10:38 
SuggestionHow to Decorate with tags PinmemberSMerrill882-Dec-11 12:16 
GeneralRe: How to Decorate with tags PinmemberEd Guzman25-Jan-12 6:58 
Questionz-index Pinmembermgonzales321-Oct-11 7:58 
AnswerRe: z-index PinmemberChiefmega19-Dec-11 16:40 
GeneralMy vote of 1 Pinmembersrinivaskumar pasumarthi18-Sep-11 23:46 
GeneralRe: My vote of 1 PinmemberEd Guzman23-Jan-12 10:29 
GeneralControl not working within an update panel Pinmembertsansoterra8-Jul-11 10:51 
GeneralIssue resolved: li.selected always false in master page PinmemberNitesh Luharuka12-May-11 14:58 
GeneralRe: Issue resolved: li.selected always false in master page PinmemberEd Guzman24-May-11 5:26 
GeneralRe: Issue resolved: li.selected always false in master page PinmemberNitesh Luharuka24-May-11 8:09 
GeneralRe: Issue resolved: li.selected always false in master page Pinmemberrajodiya23-May-12 8:26 
GeneralRe: Issue resolved: li.selected always false in master page PinmemberNitesh Luharuka23-May-12 17:46 
GeneralThanks a Lot. Pinmemberrmcomics21-Feb-11 1:07 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.141030.1 | Last Updated 1 Dec 2010
Article Copyright 2010 by Ed Guzman
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid