最近,去了新公司,由于限制了网络,有过一阵子没有写东西了,只能周末在家的时候有时间写。本想写一些最近关于学习CRM2011的学习心得,但一方面考虑到公司限网,另一方面,网上已经有大神写了非常详细的一个CRM2011编程系列,因此就打消了这个念头,只好记录下一些工作中常用到的技术点,就当备忘吧,也供大家参考。
要实现的效果如下:
(图1)
(图2)
实现思路:大家都知道,Gridview控件,生成的html代码其实就是对应的一个table。要合并某一列中数据相同的行,会用到该单元格也即td的RowSpan属性。1、当Gridview中有数据时,我先取第一行中要合并列的文本,并设置第一行中指定的列不跨行,记录下待合并列的索引位置。2、遍历Gridview中的数据,但是要从第二行开始遍历。如果有文本和前一行中指定的列文本相同,则先隐藏这一单元格中的文本,再设置上一单元格的RowSpan+1(有多少连续相同值的行,就跨多少行)。如果不同,则重新更新 要合并的文本和待合并单元格起始索引,RowSpan默认为1。3、合并单元格方法应放置在DataBind事件中。
(图1)代码如下:
/// <summary> /// 合并行(普通列) /// </summary> /// <param name="gv">Girdview对象</param> /// <param name="columnIndex">要合并的列的索引</param> public static void UnitCell(GridView gv, int columnIndex) { int i; string lastText; //合并行中列的文本 int lastCell; //待合并单元格的起始索引 if (gv.Rows.Count > 0) { lastType = gv.Rows[0].Cells[columnIndex].Text; gv.Rows[0].Cells[columnIndex].RowSpan = 1; lastCell = 0; for (i = 1; i < gv.Rows.Count; i++) { if (gv.Rows[i].Cells[columnIndex].Text == lastText) //连续行的文本相同 { gv.Rows[i].Cells[columnIndex].Visible = false; gv.Rows[lastCell].Cells[columnIndex].RowSpan++; } else { lastType = gv.Rows[i].Cells[columnIndex].Text; lastCell = i; gv.Rows[i].Cells[columnIndex].RowSpan = 1; } } } } /// <summary> /// 合并行(模板列) /// </summary> /// <param name="gv">Girdview对象</param> /// <param name="columnIndex">要合并的列的索引</param> /// <param name="lblName">模板列里面label的ID</param> public static void UnitCell(GridView gv, int columnIndex, string lblName) { int i; string lastType; //合并行中列的文本 int lastCell; //待合并单元格的起始索引 if (gv.Rows.Count > 0) { lastType = (gv.Rows[0].Cells[columnIndex].FindControl(lblName) as Label).Text; gv.Rows[0].Cells[columnIndex].RowSpan = 1; lastCell = 0; for (i = 1; i < gv.Rows.Count; i++) { if ((gv.Rows[i].Cells[columnIndex].FindControl(lblName) as Label).Text == lastText) //连续行的文本相同 { gv.Rows[i].Cells[columnIndex].Visible = false; gv.Rows[lastCell].Cells[columnIndex].RowSpan++; } else { lastType = (gv.Rows[i].Cells[columnIndex].FindControl(lblName) as Label).Text; lastCell = i; gv.Rows[i].Cells[columnIndex].RowSpan = 1; } } } } public string GetGenderName(object obj) { return Convert.ToBoolean(obj) == true ? "男" : "女"; } //为什么写在这里?这里是gridview数据绑定完之后,执行的方法。考虑到分页后,或者页面刷新等原因 protected void GridView1_DataBound(object sender, EventArgs e) { UnitCell(GridView1, 9, "lbl"); }
(图2)cs代码如下:
protected void gdvWaterFee_RowDataBound(object sender, GridViewRowEventArgs e) { if (e.Row.RowType == DataControlRowType.DataRow) { e.Row.Attributes.Add("onmouseover", "if(this!=prevselitem){this.style.backgroundColor='#Efefef'}");//当鼠标停留时更改背景色 e.Row.Attributes.Add("onmouseout", "if(this!=prevselitem){this.style.backgroundColor='#ffffff'}");//当鼠标移开时还原背景色 e.Row.Attributes.Add("onclick", e.Row.ClientID.ToString() + ".checked=true;selectx(this,11,8)"); //单击时改变行中指定列的背景色 } } protected void gdvWaterFee_DataBound(object sender, EventArgs e) { int index = 3; int endIndex = 9; for (int i = index; i <= endIndex; i++) { UnitCell(gdvWaterFee, i, index); } } /// <summary> /// 合并行(普通列) /// </summary> /// <param name="gv">Girdview对象</param> /// <param name="columnIndex">要合并的列的索引</param> /// <param name="textIndex">比较文本相同的列索引(如果此列的文本相同则合并指定列)</param> public static void UnitCell(GridView gv,int columnIndex, int textIndex) { int i; string lastText; //合并行中列的文本 int lastCell; //待合并单元格的起始索引 if (gv.Rows.Count > 0) { lastText = gv.Rows[0].Cells[textIndex].Text; gv.Rows[0].Cells[columnIndex].RowSpan = 1; lastCell = 0; for (i = 1; i < gv.Rows.Count; i++) { if (gv.Rows[i].Cells[textIndex].Text == lastText) //连续行的文本相同 { gv.Rows[i].Cells[columnIndex].Visible = false; gv.Rows[lastCell].Cells[columnIndex].RowSpan++; } else { lastText = gv.Rows[i].Cells[textIndex].Text; lastCell = i; gv.Rows[i].Cells[columnIndex].RowSpan = 1; } } } }
js代码如下:
var bgColor = '#A7CDF0'; //蓝色 var bgColor1 = '#ffffff'; //白色 var prevselitem = null; //选中行变色 参数示例:11,8 (row:点击变色的行对象,cCounts:总共的列数,cIndex:此列索引后面的列都变色) function selectx(row,cCounts,cIndex) { if (prevselitem != null) { for (var v = 0; v <= cCounts; v++) { if (prevselitem.cells.length == 5) { if (v < 5) { prevselitem.cells[v].style.backgroundColor = bgColor1; } } else { prevselitem.cells[v].style.backgroundColor = bgColor1; } } } for (var v = 0; v <= cCounts; v++) { if (row.cells.length == 5) { if (v < 5) { row.cells[v].style.backgroundColor = bgColor; } } else { if (v < 2 || v > cIndex) { row.cells[v].style.backgroundColor = bgColor; } } } prevselitem = row; }
总结:鼠标移到行上时设置该行的背景颜色,鼠标移开时,还原背景颜色。鼠标单击该行时,给该行设置颜色,并把该行存起来,当再次点击行时,先将存起来的那一行颜色复原,再给新点击的行设置颜色。如果要设置行中指定单元格的背景颜色,则只要以单元格为单位设置其背景颜色即可。
关于全选和反选功能,太简单,我这里只提一下思路。单击全选按钮时,判断该按钮是否为选中,如果为选中,则遍历该Gridview中所有的checkbox,并设置其为选中,否则设置为不选中。当单击Gridview数据行中的复选框时,再次遍历Gridview中所有复选框,如果选中的数量等于总数,则全选框选中,否则不选中。关键代码如下:
//获Ggridview中所有的复选框 sName: Gridview 的ID function getCheckbox(sName) { var aryCheckbox = new Array(); var tb = document.getElementById(sName); if (tb == null) return; var objs = tb.getElementsByTagName("input"); for (var i = 0; i < objs.length; i++) { if (objs[i].type == 'checkbox' && startsWith(objs[i].id, sName)) aryCheckbox.push(objs[i]); } return aryCheckbox; } //监听每一行的复选框,控制全选、反选按钮 function controlSelectAll(t) { var tblName, cbkAll; //Gridview ID ,全选框ID if (t == 1) { //水费 tblName = "gdvWaterFee"; cbkAll = "chkAllFee"; } else if(t==2) //代收费 { var tblName = "gdvCollFee"; var cbkAll = "chkAllColl"; } else { return; } var chks = getCheckbox(tblName); var count = 0; for (var i = 0; i < chks.length; i++) { if (chks[i].checked == true) { count++; } } if (count < chks.length) { document.getElementById(cbkAll).checked = false; } else { document.getElementById(cbkAll).checked = true; } }