最近在做电脑维修网时,需要制作一个信息订阅选择的功能,需根据数据库中的类别进行动态的生成CheckBox,以及对其赋值和读取。
格式大致为:存在数据库中必定是按照“1,2,3,4”用逗号分隔的字符串。现在要做的核心就是根据该字符串动态的给CheckBox赋值,以及把选中的CheckBox读取为其格式。
根据类别遍历生成CheckBox,首选用到的2个服务器组件并定是Repeater以及CheckBoxList。
由于此处主要展示功能性代码,由此未对页面进行任何的美化处理,页面代码如下:
<html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Repeater嵌套CheckBoxList读取赋值Demo</title> </head> <body> <form id="form1" runat="server"> <div> <asp:Repeater ID="Repeater1" runat="server" OnItemDataBound="Repeater1_ItemDataBound"> <ItemTemplate> <div style="color: Red;"> <%# Eval("Name")%>: <asp:HiddenField ID="hidID" runat="server" Value='<%# Eval("Id")%>' /> </div> <asp:Repeater ID="Repeater2" runat="server" OnItemDataBound="Repeater2_ItemDataBound"> <ItemTemplate> <div style="padding: 10px 10px;"> <%# Container.ItemIndex+1 %>、<%# Eval("Name")%>: <br /> <br /> <asp:CheckBoxList ID="cbxName" runat="server" RepeatDirection="Horizontal" RepeatLayout="Flow"> </asp:CheckBoxList> </div> </ItemTemplate> </asp:Repeater> </ItemTemplate> </asp:Repeater> <asp:Button ID="btnSubmit" runat="server" Text="提交" OnClick="btnSubmit_Click" /> </div> </form> </body> </html>
一共是三层嵌套,Repeater-Repeater-CheckBoxList,数据源使用数据库比较麻烦,因此作为Demo,随便虚拟一个数据源即可。如下是数据源生成代码:
/// <summary> ///Entity 的摘要说明 /// </summary> public class Entity { private int _id; /// <summary> /// 主键 /// </summary> public int Id { get { return _id; } set { _id = value; } } private string _name; /// <summary> /// 名称 /// </summary> public string Name { get { return _name; } set { _name = value; } } private int _parent; /// <summary> /// 父节点 /// </summary> public int Parent { get { return _parent; } set { _parent = value; } } private bool _check; /// <summary> /// 选中状态 /// </summary> public bool Check { get { return _check; } set { _check = value; } } private List<Entity> _list; /// <summary> /// 动态生成的集合 /// </summary> public List<Entity> List { get { return _list; } set { _list = value; } } public Entity() { } /// <summary> /// 获取虚拟列表 /// </summary> public void GetList() { List = new List<Entity>(); int primaryKey = 1; for (int i = 0; i < 2; i++) { Entity obj = new Entity(); obj.Id = primaryKey; obj.Name = "电脑维修网" + primaryKey; obj.Parent = 0; obj.Check = true; List.Add(obj); primaryKey++; for (int j = 0; j < 3; j++) { Entity obj2 = new Entity(); obj2.Id = primaryKey; obj2.Name = "维修类型" + primaryKey; obj2.Parent = obj.Id; obj2.Check = true; List.Add(obj2); primaryKey++; for (int m = 0; m < 2; m++) { Entity obj3 = new Entity(); obj3.Id = primaryKey; obj3.Name = "维修项目" + primaryKey; obj3.Parent = obj2.Id; obj3.Check = true; List.Add(obj3); primaryKey++; } } } } }
后台代码如下:
Entity entity = new Entity(); protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { //获取虚拟数据集合 entity.GetList(); //Repeater数据绑定 Repeater1.DataSource = entity.List.Where(o => o.Parent == 0); Repeater1.DataBind(); //给CheckBoxList赋值 SetCheckBoxValue("3,4,6,7"); } } /// <summary> /// 根据后台返回的数据列,为复选框赋值 /// </summary> /// <param name="follow">以逗号分割的字符串</param> private void SetCheckBoxValue(string followStr) { //如果字符为空,不做任何操作 if (string.IsNullOrEmpty(followStr)) { return; } string[] follow = followStr.Split(','); /* * 首先说明下层级关系 * 第一层为Repeater,里边继续嵌套一个Repeater,然后在嵌套的Repeater中嵌套CheckBoxList * Repeater-Repeater-CheckBoxList * 理解了嵌套关系,就很容易理解应该去如何遍历 */ //遍历主Repeater,然后对其子Repeater进行遍历,获取到CheckBoxList进行赋值 for (int i = 0; i < Repeater1.Items.Count; i++) { //获取子Repeater Repeater rep2 = ((Repeater)Repeater1.Items[i].FindControl("Repeater2")); //对子Repeater进行遍历,获取到CheckBoxList进行赋值 for (int j = 0; j < rep2.Items.Count; j++) { //获取第二层Repeater的CheckBoxList CheckBoxList cbxThreeList = ((CheckBoxList)rep2.Items[j].FindControl("cbxName")); foreach (ListItem item in cbxThreeList.Items) { foreach (string s in follow) { if (item.Value == s) { item.Selected = true; } } } } } } /// <summary> /// 获得前台选中值 /// </summary> /// <returns>获取选中CheckBoxList的值,并用逗号分隔</returns> private string GetCheckBoxValue() { string follow = ""; for (int i = 0; i < Repeater1.Items.Count; i++) { Repeater rep2 = ((Repeater)Repeater1.Items[i].FindControl("Repeater2")); for (int j = 0; j < rep2.Items.Count; j++) { CheckBoxList cbxThreeList = ((CheckBoxList)rep2.Items[j].FindControl("cbxName")); foreach (ListItem item in cbxThreeList.Items) { if (item.Selected == true) { follow += item.Value + ","; } } } } return follow.TrimEnd(','); } /// <summary> /// 第一层Repeater数据绑定时,进行第二层Repeater数据的绑定 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e) { // ItemDataBound事件触发的项包括页眉、页脚、分隔符和项。 // 对类型进行筛选,只执行类型为项或者交替单元格中的项。 if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem) { Repeater rep = ((Repeater)e.Item.FindControl("Repeater2")); //不用在前台输出隐藏标签,直接从数据源中读取数据,这样省去了前台的标签,可能有利于优化 //Entity rowDate = e.Item.DataItem as Entity; //rep.DataSource = entity.List.Where(o => o.Parent == rowDate.Id); //在前台生成一个隐藏标签用于存值 HiddenField hidID = ((HiddenField)e.Item.FindControl("hidID")); rep.DataSource = entity.List.Where(o => o.Parent == Convert.ToInt16(hidID.Value)); rep.DataBind(); } } /// <summary> /// 第二层Repeater数据绑定时,进行第三层CheckBoxList数据的绑定 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void Repeater2_ItemDataBound(object sender, RepeaterItemEventArgs e) { // This event is raised for the header, the footer, separators, and items. // Execute the following logic for Items and Alternating Items. if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem) { CheckBoxList cbxName = ((CheckBoxList)e.Item.FindControl("cbxName")); cbxName.DataTextField = "Name"; cbxName.DataValueField = "Id"; //不用在前台输出隐藏标签,直接从数据源中读取数据,这样省去了前台的标签,可能有利于优化 Entity rowDate = e.Item.DataItem as Entity; cbxName.DataSource = entity.List.Where(o => o.Parent == rowDate.Id); cbxName.DataBind(); } } /// <summary> /// 提交按钮执行的事件,用于显示勾选的项 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void btnSubmit_Click(object sender, EventArgs e) { HttpContext.Current.Response.Write("<script language='javascript'>alert('选择的项:" + GetCheckBoxValue() + "');</script>"); }
动态生成CheckBox的核心代码都在ItemDataBound事件中,赋值和读取核心代码在方法SetCheckBoxValue与GetCheckBoxValue中。
在Repeater1_ItemDataBound事件中有2个小技巧,那就是如何得到行数据的值,这里我在需要读取ID。
有2种解决方案:
第一种使用e.Item.DataItem属性,直接从绑定到Repeater的数据源中读取该行对应的数据对象,通过把其转换为具体的对象来进行数据的读取。个人比较喜欢用该方法。代码相对而言比较简洁。
第二种直接就是在前台放一个HiddenField把ID隐藏在其中,后台通过获取该组件,然后读取该组件的值进行数据的读取,此方案使用起来比较繁琐,个人不推荐使用。
不知是否还有其他读取方案,有兴趣的朋友可以研究研究。如果你有更好的解决方案,希望不要吝啬,能拿出来探讨探讨,以便代码的优化。毕竟学习本来就是一件分享的事情。