在项目开发中,一般情况下都使用TreeView控件,实现级联选中效果更简单方便,但是为了显示内容更加直观而尝试了使用gridview来实现。
1、首先实现合并相同行,方法代码如下。
///<summary>
///合并行
///</summary>
///<paramname="gvw">需要合并的GridView</param>
///<paramname="sCol">要合并开始列</param>
///<paramname="eCol">要合并的结束列</param>
public static voidMergeRows(GridView gvw,int sCol,int eCol)//gvw需要合并的GridView,sCol要合并开始列(从0开始),eCol要合并的结束列
{
//如果第3列相同,则第1、2、3列合并单元格,如果第1列,则第0、1合并单元格
for (int rowIndex = gvw.Rows.Count - 2; rowIndex >= 0;rowIndex--)
{
GridViewRowrow = gvw.Rows[rowIndex];
GridViewRowpreviousRow = gvw.Rows[rowIndex + 1];
for(int i = sCol; i < eCol + 1; i++)
{
if(row.Cells[i].Text !=""&& row.Cells[i].Text !=" ")
{
if(row.Cells[i].Text == previousRow.Cells[i].Text)
{
row.Cells[i].RowSpan =previousRow.Cells[i].RowSpan < 1 ? 2 : previousRow.Cells[i].RowSpan + 1;
previousRow.Cells[i].Visible = false;
row.Cells[i -1].RowSpan = previousRow.Cells[i - 1].RowSpan < 1 ? 2 : previousRow.Cells[i- 1].RowSpan + 1;
previousRow.Cells[i -1].Visible = false;
for (int j = row.RowIndex +row.Cells[i].RowSpan - 1; j >= row.RowIndex; j--)
{
CheckBox cbx1 =newCheckBox();
CheckBox cbx2 =newCheckBox();
CheckBox cbx3 =newCheckBox();
if (i == 1)
{
cbx2 =gvw.Rows[j].Cells[i + 1].FindControl("cb_Check2")asCheckBox;
cbx1 =row.Cells[i - 1].FindControl("cb_Check1")asCheckBox;
cbx2.Attributes.Remove("parentId");
cbx2.Attributes.Add("parentId",cbx1.ClientID);
}
else
{
cbx3 =gvw.Rows[j].Cells[i + 1].FindControl("cb_Check3")asCheckBox;
cbx2 =row.Cells[i - 1].FindControl("cb_Check2")asCheckBox;
cbx3.ToolTip =cbx2.ClientID;
cbx3.Attributes.Remove("parentId");
cbx3.Attributes.Add("parentId",cbx2.ClientID);
}
}
}
}
}
}
}
2、为gridview中的复选框添加js事件,并初始化parentId属性(我自己命名的属性,存储父级复选框的id值,而这样赋值的结果是给复选框加了一个span标签:
<spantitle="GridView1_ctl02_cb_Check2"parentId="GridView1_ctl02_cb_Check2"><inputid="GridView1_ctl02_cb_Check3"type="checkbox"name="GridView1$ctl02$cb_Check3"onclick="selectIndex('GridView1','GridView1_ctl02_cb_Check3');"/></span>)
代码如下:
protected void GridView1_RowDataBound(objectsender, GridViewRowEventArgs e)
{
//禁用复选框(已经下载或已经上传的项目不能再下载)
if(e.Row.RowType == DataControlRowType.DataRow)
{
CheckBoxcbx1 = e.Row.FindControl("cb_Check1")asCheckBox;
CheckBoxcbx2 = e.Row.FindControl("cb_Check2")asCheckBox;
CheckBoxcbx3 = e.Row.FindControl("cb_Check3")asCheckBox;
stringstate = e.Row.Cells[7].Text.Trim();
if(state == "已下载"|| state == "已上传")
cbx3.Enabled = false;
else
cbx3.Enabled = true;
//根据子节点的enable属性设置父节点的enable
ScriptManager.RegisterStartupScript(Page,GetType(),"","SetDisabled('" + GridView1.ClientID +"','3');",true);
//给复选框添加js事件
cbx1.Attributes.Add("onclick","selectIndex('"+ GridView1.ClientID +"','" +cbx1.ClientID +"')");
cbx2.Attributes.Add("onclick","selectIndex('"+ GridView1.ClientID +"','" +cbx2.ClientID +"')");
cbx3.Attributes.Add("onclick","selectIndex('"+ GridView1.ClientID +"','" +cbx3.ClientID +"')");
cbx2.Attributes.Add("parentId", cbx1.ClientID);
cbx3.Attributes.Add("parentId", cbx2.ClientID); ;
}
}
3、 Js方法1:unChecked(GVID,CBXID),参数分别代表:gridview的id及复选框id。反选该复选框时,则其父级复选框也应反选。代码如下:
function unChecked(GVID, CBXID) {
/*
如果是反选,则将父项也反选;
*/
checkbox2 =document.getElementById(CBXID);
if(!checkbox2.checked) {
try{
varparent = document.getElementById(checkbox2.parentNode.attributes("parentId").value);
parent.checked = false;
unChecked(GVID,checkbox2.parentNode.attributes("parentId").value);
}
catch(Error) { }
}
}
4、 Js方法2:DoChecked(GVID,CBXID),参数分别代表:gridview的id及复选框id。选中该复选框时,如果该级复选框全部选中,则其父级复选框也应选中。代码如下:
functionDoChecked(GVID, CBXID) {
/* 如果是选中,则判断父项的所有enable=true的子项是否全部选中,如果是,则选中父项 */
checkbox2 =document.getElementById(CBXID);
if(checkbox2.checked) {
chsParent =document.getElementById(GVID).getElementsByTagName("INPUT");
j = 0;
varflag = true;
for(j = 0; j < chsParent.length; j++) {
if(!chsParent[j].disabled) {
try {
var parentId = chsParent[j].parentNode.attributes("parentId").value;
if (parentId == checkbox2.parentNode.attributes("parentId").value &&!chsParent[j].checked) {
flag = false;
}
} catch (Error) { }
}
}
if(flag) {
try{
var parent = document.getElementById(checkbox2.parentNode.attributes("parentId").value);
parent.checked = true;
DoChecked(GVID,checkbox2.parentNode.attributes("parentId").value);
}
catch(Error) { }
}
}
}
5、 Js事件1:selectIndex(GVID,CBXID, TYPE),参数分别代表:gridview的id、复选框id及类型。通过递归实现选中该复选框,则其所有子级复选框选中,反选该复选框,则其所有子级复选框反选;同时对触发事件的复选框,执行js方法1及方法2。使用type参数就是为了区别传入的CBXID参数是触发事件的复选框,还是递归时的子级复选框,当type== undefined时,为触发事件的复选框。具体代码如下:
functionselectIndex(GVID, CBXID, TYPE) {
varcheckbox1 = document.getElementById(CBXID);
if(document.getElementById(GVID) !=null) {
chs =document.getElementById(GVID).getElementsByTagName("INPUT");
n = 0;
for(i = 0; i < chs.length; i++) {
if(!chs[i].disabled) {
/*
把子项的选中状态与本项状态一致
*/
try {
var parentId = chs[i].parentNode.attributes("parentId").value;
if (parentId == CBXID) {
chs[i].checked= document.getElementById(CBXID).checked;//递归后checkbox1发生变化,所以不能直接用checkbox1
var m = i;
TYPE = 1;
selectIndex(GVID, chs[i].attributes("id").value,1);
TYPE =undefined;
i = m;
}
} catch (Error) { }
}
}
}
if(TYPE == undefined) {
unChecked(GVID, CBXID);
DoChecked(GVID, CBXID);
}
}
6、 Js方法3:SetDisabled(GVID,index)参数分别代表:gridview的id,gridview中复选框的最子级别的索引,级别从1开始,本文的例子最子级别的索引为3。(如果实现此方法,则复选框的命名规则必须为:" cb_Check"+ index)此方法是为了初始化gridview中的复选框的disabled属性值:如果子节点复选框disabled全为true,则父节点也不可用,否则父节点可用。在绑定完gridview时,调用此方法。具体代码如下:
functionSetDisabled(GVID, index) {
/*
index为checkbox最子级别,并且最父级从1开始
如果子节点复选框disabled全为true,则父节点也不可用,否则父节点可用
*/
varstrCBXID = "Check" + index; //复选框的id后缀名
vararr = new Array();
varparentId;
chsChild =document.getElementById(GVID).getElementsByTagName("INPUT");
j = 0;
//只循环最后一列checkbox,然后再通过递归
for(j = 0; j < chsChild.length; j++) {
if(chsChild[j].disabled && chsChild[j].attributes("id").value.indexOf(strCBXID)) {
try{
parentId =chsChild[j].parentNode.attributes("parentId").value;
var isHave =false;
for (var m = 0; m < arr.length;m++) {
if (parentId == arr[m]) {
isHave = true;
break;
}
}
if (isHave)
continue;
else {
var flag =true;
chsBrother =document.getElementById(GVID).getElementsByTagName("INPUT");
for (u = 0; u < chsBrother.length; u++) {
try {
if (parentId == chsBrother[u].parentNode.attributes("parentId").value &&!chsBrother[u].disabled) {
flag = false;
}
} catch (Error) { }
}
if (flag) {
varobjParent = document.getElementById(parentId);
objParent.disabled = true;
}
if (parentId != undefined && parentId !='')
arr.push(parentId);
}
} catch(Error) {
}
}
}
if(index > 1)
SetDisabled(GVID, index - 1);
}
结语:在开发过程中,经常会遇到在网上找不到解决方案的新问题,那就需要一种勇于尝试和挑战的心态。在尝试的过程中,也要考虑代码复用性,以便可以解决这一类问题。当然我写的肯定不是最好最简洁的代码,也希望各位领导及同事能给予更多的建议和意见。