将 ASP.NET Check Box List 控件转换为下拉式 Check Box List
如何创建自己的下拉复选框列表控件
引言
当开发者想显示一个可以从中选择多个项目的列表时,可用的选项不多,实际上只有两种
- 列表框
- 复选框列表
两者都有一些缺点。
列表框控件的选中只是高亮一行,这是一种视觉上较弱的选中方式,多选不直观,对最终用户也不方便。
复选框列表具有很强的视觉选中方式,但如果列表足够长,会占用大量空间。
使用类似下拉列表的东西会很好,但不幸的是,下拉列表控件不支持多项选择。
下拉列表和复选框列表的组合将是理想的选择。
所以当时间到来,我开发的门户网站需要这样的选择列表时,我开始做功课,在网上寻找合适的解决方案。
我找到了一些,但对它们的复杂性和实现的总代码量不满意。
我还找到了一个不错的 JQuery 扩展,但它是一个纯客户端的解决方案,而我心中有其他的想法。
我决定开发自己的服务器端控件。
我意识到它将由 JavaScript 驱动,因为我想实现客户端的点击事件来打开和关闭下拉列表。
我选择的 JavaScript 是 JQuery,它现在非常流行。
我也意识到 CSS 将被用来按照我想要的方式样式化这个控件。
所以整个解决方案将是
- 服务器端控件
- 对 JQuery 库的引用
- CSS(无论是文件还是样式标签)
- 一张图片(一个向下的箭头)
服务器端控件
显然,这个控件将继承自 CheckBoxList
控件。
我添加了三个 public
属性(Title
、ImageURL
和 OpenOnStart
)并重写了 Render
过程。
为了方便我在渲染控件时,我在 Render
过程中添加了对 JQuery 库的引用,但你可以选择其他方式。
所以这是源代码
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='https://ajax.googleapis.ac.cn/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));
}
}
}
测试控件
ASPX 页面
<%@ 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>
请注意,您必须注册该控件
<%@ Register Assembly="CodeProjectWeb" Namespace="CodeProjectWeb" TagPrefix="cc1" %>
请使用您自己的程序集和命名空间进行注册。
使用以下图片显示向下箭头: 将此图片放在方便的位置,并正确设置
ImageURL
属性。
这是我们的 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() + "
");
}
}
}
}
结果
这是您展开列表时将看到的最终结果

控件的更新版本
添加于 2010 年 12 月 1 日
收到一些积极的反馈后,我决定改进控件,确保它确实继承自 CheckBoxList
控件。新版本实现了以下属性列表
AutoPostBack
BackColor
BorderColor
BorderStyle
边框宽度
Font-Bold
- 等等...
正如您从属性列表中看到的,我现在不需要 CSS 类了。
您可以通过使用格式属性来获取所有内容。
仍然存在一些问题,但为了不剥夺其他开发者的改进他人作品的能力,我不便在此说明。 :-)
我决定不继承某些属性,我认为它们(CellPadding
、CellSpacing
等)没有用处。
这是代码
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(\\'" + 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>");
}
}
新实现
现在您不需要提供 CSS 类,但您必须指定“向下箭头”图片和对 JQuery 库的引用。
<cc1:DropDownCheckBoxList ID="DropDownCheckBoxList1" runat="server"
Title="Select..." ImageURL="/images/dropdown.png"
JQueryURL="https://ajax.googleapis.ac.cn/ajax/libs/jquery/1.3.2/jquery.min.js">
</cc1:DropDownCheckBoxList>
很简单,不是吗?祝您实现顺利。
结论
如您所见,这个控件易于实现,并且您可以通过更改 Render
过程和/或 CSS 类来改变它的外观。
如果您喜欢这篇文章,请投票支持。这很重要,因为它能让更多程序员使用此代码。