当前位置: 首页 > 图文教程 > 网络编程 > ASP.NET > 使CheckBoxList的Attributes属性生效(修改微软的一个bug)

ASP.NET
使用函数传递参数来执行相应的数据库操作
如何实现在窗体和窗体之间进行传递数据
ASP.NET中文显示之两种解决方法
ASP.NET、JSP及PHP之间的抉择
ASP.NET 2.0发送电子邮件中存在的问题
谈谈HtmlControl与WebControl的区别与用途
从ASP.NET 1.1升级到ASP.NET 2.0要考虑的Cookie问题
通过系统配置来提高ASP.NET应用程序的稳定性
妙用ASP2.0中的URL映射改变网址
AJAX实现web页面中级联菜单的设计
ASP.NET跨页面传值技巧总结
再议ASP.NET DataGrid控件中的“添加新行”功能
Geometry 对象浅析
重构CollapsibleSplitter
如何利用.NET Framework使用RSS feed
ASP.NET获取IP与MAC地址的方法
在ASP.NET 2.0中使用样式、主题和皮肤
ASP.NET中为GridView添加删除提示框
ASP.NET 2.0,无刷新页面新境界
看看一个.net版对话框控件

ASP.NET 中的 使CheckBoxList的Attributes属性生效(修改微软的一个bug)


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-09-13   浏览: 45 ::
收藏到网摘: n/a

本文将描述如何使CheckBoxList中的Item添加的Attribute在客户端生效,CheckBoxList是一个非常好用的组件,它支持数据绑定等特性。但是他和DropDownList有同样的一个问题,就是当我们向它们的Items里面Add项目的时候,如果希望给这些Item添加客户端行为,这些行为并不能体现在客户端,我们通常使用的方法如下:
HTML页面部分如下:
<asp:CheckBoxList id="CheckBoxList1" runat="server">
<asp:ListItem Value="1">1</asp:ListItem>
<asp:ListItem Value="2">2</asp:ListItem>
<asp:ListItem Value="3">3</asp:ListItem>
</asp:CheckBoxList>
我们在Page_Load里面添加如下代码:
foreach(ListItem item in this.CheckBoxList1.Items){
item.Attributes.Add("onclick","alert('"+item.Text+"')");
}
这样做的目的是:当我们点击CheckBox的时候希望alert出来我们选中的CheckBox的内容,当然还有其他的一些更有用的应用。但是实际上这段代码是不能正常工作的。我们在客户端点击CheckBox的时候看不到提示信息,同样不论你向Attributs中添加什么都不会有任何反应的。同样的问题也存在于其他的List控件中,比如:DropDownList等。
下面是这个页面呈现的客户端脚本:
<table id="CheckBoxList1" border="0">
<tr><td><input id="CheckBoxList1_0" type="checkbox" name="CheckBoxList1:0" /><label for="CheckBoxList1_0">1</label></td>
</tr>
<tr><td><input id="CheckBoxList1_1" type="checkbox" name="CheckBoxList1:1" /><label for="CheckBoxList1_1">2</label></td>
</tr>
<tr><td><input id="CheckBoxList1_2" type="checkbox" name="CheckBoxList1:2" /><label for="CheckBoxList1_2">3</label></td>
</tr>
</table>
可以看出来这里并没有我们期望的onclick事件。
下面我将提供一种方法来完善这个控件,既然是完善,那么我会保持该控件原有的所有特性并修复上面这个bug(我认为应该是一个bug),可能已经有人想到了使用什么方法,对,我将使用继承的方式复用这个控件。并在我们的新控件上做些手脚,使它更好用,我命名这个控件名叫NewCheckBoxList。
我们首先从分析客户端代码开始,我们发现在服务器上写的代码在客户端没有任何表现,那么怎么才能表现出来呢?这里我将重写该组件的Render方法,来完成最终的目的。下面就描述一下我的思路,首先我会从Render中将本来应该输出到页面的流,输出到一个StringBuilder里面,这样我就有机会编辑这个StringBuilder来完成剩下的工作,获得这个StringBuilder之后我们将按照我们希望的逻辑来为这个字符串添加内容,当内容添加完之后将这个字符串写到控件的输出流中即可。
下面是控件的实现代码:

using System;

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Text;

namespace Cuike519.Web.UI.WebControls {

namespace Cuike519.Web.UI.WebControls {
/// <summary>
/// Summary description for NewCheckBoxList.
/// </summary>
[DefaultProperty("Text"),
ToolboxData("<{0}:NewCheckBoxList runat=server></{0}:NewCheckBoxList>")]
public class NewCheckBoxList : System.Web.UI.WebControls.CheckBoxList {

protected override void Render(HtmlTextWriter writer) {

protected override void Render(HtmlTextWriter writer) {
StringBuilder sb = new StringBuilder();
System.IO.TextWriter tw = new System.IO.StringWriter(sb);
HtmlTextWriter OriginalStream = new HtmlTextWriter(tw);
base.Render(OriginalStream);
string s = sb.ToString();
int start = 0;
int end = s.Length;
for(int i = 0;i< this.Items.Count;i++){
start = s.IndexOf("<input",start,end-start);
StringBuilder sbItemAttribute = new StringBuilder();
this.Items[i].Attributes.Render(new HtmlTextWriter(new System.IO.StringWriter(sbItemAttribute)));
s = s.Insert(start+7,sbItemAttribute.ToString()+" ");
start = s.IndexOf("/>",start,s.Length-start);
end += sbItemAttribute.Length+1;
}
writer.Write(s);
}

}
}

代码说明如下:
我将构造一个StringBuilder来保存该控件呈现的内容(这个内容并不完整需要修改),我们利用base.Render将原始流写到sb里面,接着会获得其字符串,然后我们会在整个字符串中的指定位置查找对应的input,这里的算法应该还可以优化,有兴趣的网友可以试试。我会找到上一个input结尾的/>作为下一个查找的开始。在找到字符串之后我将利用item.Attribute的Render方法将我们在叶面中添加的内容输出到一个新的StringBuilder中(过程类似前面),接着我们会将这个输出写到原始流字符种合适的位置。到此控件算是修改完成了,下面是测试结果:
我们在使用该控件的页面中添加一个下面的指令:
<%@ Register TagPrefix="ck" Namespace="Cuike519.Web.UI.WebControls" Assembly="Test" %>
指明一些必要的参数,这里的Test就是我的测试工程生成的Assembly。页面的控件部分如下:
<ck:NewCheckBoxList id="NewCheckBoxList1" runat="server">
<asp:ListItem Value="a">a</asp:ListItem>
<asp:ListItem Value="b">b</asp:ListItem>
<asp:ListItem Value="c">c</asp:ListItem>
</ck:NewCheckBoxList>
我们在页面的Load写上面同样的代码:
foreach(ListItem item in this.NewCheckBoxList1.Items){
item.Attributes.Add("onclick","alert('"+item.Text+"')");
}
同样的代码只是更换了控件,让我们看看运行效果,下面是产生的客户端脚本:
<table id="NewCheckBoxList1" border="0">
<tr><td><input onclick="alert('a')" id="NewCheckBoxList1_0" type="checkbox" name="NewCheckBoxList1:0" /><label for="NewCheckBoxList1_0">a</label></td>
</tr>
<tr><td><input onclick="alert('b')" id="NewCheckBoxList1_1" type="checkbox" name="NewCheckBoxList1:1" /><label for="NewCheckBoxList1_1">b</label></td>
</tr>
<tr><td><input onclick="alert('c')" id="NewCheckBoxList1_2" type="checkbox" name="NewCheckBoxList1:2" /><label for="NewCheckBoxList1_2">c</label></td>
</tr>
</table>

是不是和上一个不一样?J 同样的方法也适用于DropDownList等组件。
下面是NewDropDownList实现的部分代码,替换NewCheckBoxList的对应部分即可:
for(int i = 0;i< this.Items.Count;i++){
start = s.IndexOf("<option",start,end-start);
StringBuilder sbItemAttribute = new StringBuilder();
this.Items[i].Attributes.Render(new HtmlTextWriter(new System.IO.StringWriter(sbItemAttribute)));
s = s.Insert(start+7,sbItemAttribute.ToString()+" ");
start = s.IndexOf("</option>",start,s.Length-start);
end += sbItemAttribute.Length+1;
}
该文章灵感来源于CSDN的网友提问。