关于一个无限分类的多选,单选相关的控件

最近在一个项目中需要用到无限分类的平铺多选,单选这些功能,查了一些资料,结果大都是一些用IFrame这样的东西做的,虽然用起来直观,但本人更喜欢集成控件形式的,于是抽了一些时间做了一个.思路是利用控件+JS+不同的无限分类表,支持一页多控件,支持不同的无限分类表.效果图如下:

当这些父类被选择时,子类都被选择.当这些父类取消选择时,其下所有子类都被取消选择.

代码如下:

控件behind代码CS:

 

ContractedBlock.gif ExpandedBlockStart.gif MultiSelectItems.ascx.cs
  1  using  System;
  2  using  System.Collections;
  3  using  System.Collections.Generic;
  4  using  System.Configuration;
  5  using  System.Data;
  6  using  System.Linq;
  7  using  System.Web;
  8  using  System.Web.Security;
  9  using  System.Web.UI;
 10  using  System.Web.UI.HtmlControls;
 11  using  System.Web.UI.WebControls;
 12  using  System.Web.UI.WebControls.WebParts;
 13  using  System.Xml.Linq;
 14  using  Models;
 15 
 16  public   partial   class  MultiSelectItems : System.Web.UI.UserControl
 17  {
 18       public  List < Groups >  groupList {  get set ; }   
 19 
 20       public   string  hasSel
 21      {
 22           set
 23          {
 24               if  ( ! string .IsNullOrEmpty(value))
 25              {
 26                   // 绑定已选数据                    
 27                  value  =  value.Trim( ' , ' );
 28                   string [] hasSels  =  value.Split( ' , ' );
 29                   foreach  ( string  s  in  hasSels)
 30                  {
 31                      scriptStr  +=   " document.getElementById('checkItems "   +  tableName  +  s  +   " ').checked=true;\r\n " ;
 32                      scriptStr  +=   " checkProperty(' "   +  tableName  +   " ', "   +  s  +   " ,' "   +  controlName  +   " ');\r\n " ;
 33                  }
 34                  scriptStr  +=   " document.getElementById('checkeds "   +  tableName  +   " ').value=' "   +  value  +   " ,';\r\n " ;
 35              }
 36          }
 37      }
 38       public   string  tableName {  get set ; }
 39       public   string  controlName {  get set ; }
 40       public   string  scriptStr  =   string .Empty;
 41       public   string  multiItemsInnerHtml  =   string .Empty;
 42       protected   void  Page_Load( object  sender, EventArgs e)
 43      {
 44           // 此控件配合JS使用
 45           // 使用方法:
 46           // 在页面顶部加载此控件:<%@ Register Src="~/controls/MultiSelectItems.ascx" TagName="mi" TagPrefix="MultiSelectItem" %>
 47           // 在head中加载相应JS:<script language="javascript" src="/controls/MultiSelectItems.js" type="text/javascript"></script>
 48           // 在页面相关位置放置此控件:<MultiSelectItem:mi runat="server" ID="miArea" />ID不受限制
 49           // 配置一些属性
 50           // miArea.st = SysTable.AreaGroups; // 加载哪个表          
 51           // miArea.controlName = "checkedsAreaGroups"; // 要获取值的text控件名
 52           // miArea.BindData(); // 绑定初始数据
 53           // 如果是修改选项,可以设置已有选项:miArea.hasSel = sm.Area_Items;
 54           // 获取该控件的值,这个名称就是刚刚配置的名称:Request.Form["checkedsAreaGroups"]
 55      }
 56       ///   <summary>
 57       ///  绑定初始的多选表单数据,这些数据都是未被选择的,如果要选择数据,请设置该对象相关实例的hasSel属性
 58       ///   </summary>
 59       public   void  BindData()
 60      {
 61           string  brStr  =   string .Empty;
 62           string  clickStr  =   string .Empty;
 63           string  tpGroupName  =   string .Empty;
 64           string  tpBox  =   string .Empty;
 65           if  (groupList  !=   null )
 66          {
 67               foreach  (Groups gp  in  groupList)
 68              {
 69                  brStr  =   string .Empty;               
 70                  clickStr  =   " checkAllSubProperty(' "   +  tableName  +   " ',' "   +  gp.GroupId  +   " ',' "   +  controlName  +   " ') "  ;
 71                  tpBox  =   " <input type='checkbox' name='checkItems "   +  tableName  +   " ' id='checkItems "   +  tableName  +  gp.GroupId  +   " ' value=' "   +  gp.ParentStr  +  gp.GroupId  +   " ' οnclick=\ ""  + clickStr +  " \ "  />\r\n " ;
 72                   if  (gp.Route  ==   1 ) {
 73                      tpGroupName  =  gp.GroupName.Substring( 1 );
 74                  }
 75                   else   if  (gp.Route  ==   2 )
 76                  {
 77                      tpGroupName  =  gp.GroupName.Substring( 1 );                   
 78                  }
 79                   else  {
 80                      tpGroupName  =  gp.GroupName.Substring(gp.Route  -   1 );                   
 81                  }
 82 
 83 
 84                   if  (gp.Route  ==   1 )
 85                  {
 86                      brStr  =   " <br /> " ;
 87                      multiItemsInnerHtml  +=  brStr  +  tpBox  +   " <span style='color:#FF7500;font-weight:bold;'> "   +  tpGroupName  +   " </span> " ;
 88                  }
 89                   else
 90                  {
 91                       if  (groupList.Where(c  =>  c.ParentId  ==  gp.GroupId).Count()  >   0 )
 92                      {
 93                          brStr  =   " <br /> " ;
 94                          multiItemsInnerHtml  +=  brStr  +  tpBox  +   " <span style='font-weight:bold;'> "   +  tpGroupName  +   " </span> " ;
 95                      }
 96                       else
 97                      {
 98                          multiItemsInnerHtml  +=   tpBox  +  tpGroupName;
 99                      }                    
100                  }
101                  multiItemsInnerHtml  +=   " &nbsp;&nbsp; " ;
102                  multiItemsInnerHtml  +=  brStr;
103              }
104          }
105      }
106  }

 

html代码很简单:

 

ContractedBlock.gif ExpandedBlockStart.gif MultiSelectItems.ascx
<% @ Control Language = " C# "  AutoEventWireup = " true "  CodeBehind = " MultiSelectItems.ascx.cs "  Inherits = " MultiSelectItems "   %>
< div  id ="MultiItems<%=tableName%>" > <% = multiItemsInnerHtml %> </ div >
< input  type ="hidden"  name ="<%=controlName%>"  id ="<%=controlName%>"  value =""   />
< script  language ="javascript"  type ="text/javascript" >
<%= scriptStr %>
</ script >

 

接下来是相关的JS,注意,不论一个页面调用几次这个控件,此JS只加载一次

 

ContractedBlock.gif ExpandedBlockStart.gif MultiSelectItems.js
     function  checkAllSubProperty(tableName,groupid,checkedsControlName){
        
var  checkedControl  =  document.getElementById( " checkItems "   +  tableName  +  groupid);
        
var  items  =  document.getElementsByName( " checkItems "   +  tableName);
        
var  checkeds  =  document.getElementById(checkedsControlName);
        
if (checkedControl.checked){
            checkeds.value 
+=  groupid  +   ' , ' ;
        }
else {
            checkeds.value 
=  checkeds.value.replace(groupid  +   " , " , "" );
        }
        
for ( var  i = 0 ;i < items.length;i ++ ){
            
if (items.item(i).value.indexOf( ' , '   +  groupid  +   ' , ' >   - 1 ){
                
var  insertStr  =  items.item(i).value.substring(items.item(i).value.lastIndexOf( ' , ' +   1 ,items.item(i).value.length)  +   ' , ' ;
                
if (checkedControl.checked){
                    items.item(i).checked 
=   true ;       
                    
if (checkeds.value.indexOf(insertStr)  <   0 ){
                        checkeds.value 
+=  insertStr;
                    }
                }
else {
                    items.item(i).checked 
=   false
                    checkeds.value 
=  checkeds.value.replace(insertStr, "" );
                }
            }
        }        
    }

 

因为是基于.net 3.5的Linq做的控件,所以,此控件必须运行在装有3.5类库的机器上,而且,因为无限分类的数据库结构大家都清楚.是这样的:

稍微解释一下各字段含义:

GroupId:这是分类的主ID,自动增加,主键.

GroupName:这是分类的名字.

ParentId:这是父类的ID,

ParentStr:这是从根类--->父类---->父类....--->本类的父类的路径,以0开始,以,结束,例如0,2,10,22,这从算法上讲叫静态冗余字段,用来快速查找某个类的所有子类.例如要查找GroupId为2的所有子类,可以这样写语句:select top xx * from 表名 where ParentStr like '%,2,%',是不是比一般的遍历要快很多?

Route:这是指示该类的路径深度,如果是根类,则为1,如果是1级子类,则为2,依此类推,此字段主要用于快速查找某一级别的所有子类.

至于这个无限分类的维护,大家可以各显其能去优化.目前我的维护是采用缓存+List<>+ORM

 

 我写的东西大都是日常工作中用得比较多的,而且,相对来说,我会比较偷懒,例如,减少计算,减少数据库访问等.而且,本人不喜欢一个大括号里有很多条语句的代码方式.这样的代码比较难维护.如果我看到一个if或者while后接了一个大括号,然后整屏都看不到它的结束符.我会BS这段代码的作者.

 

 

f人要

转载于:https://www.cnblogs.com/CoreCaiNiao/archive/2009/12/01/1614665.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值