using DevExpress.Web.ASPxGridView; using System.Collections.Generic; using System.Web.UI.WebControls; using System.Web.UI; using System; namespace Lcerp.Common { public class ASPxGridViewHelper { #region 基本配置 #region 多表头 string header; bool isOpenMutiHeader = false; #endregion #region 合并单元格 bool isOpenMergeCell = false; string fieldName; int[] notMergeNumbers = null; ASPxGridView grid; public ASPxGridView Grid { get { return grid; } } Dictionary<GridViewCommandColumn, TableCell> commandCells = new Dictionary<GridViewCommandColumn, TableCell>(); Dictionary<GridViewDataColumn, TableCell> mergedCells = new Dictionary<GridViewDataColumn, TableCell>(); Dictionary<TableCell, int> cellRowSpans = new Dictionary<TableCell, int>(); #endregion #endregion #region 外部调用入口(初始化) public ASPxGridViewHelper(ASPxGridView grid) { this.grid = grid; } /// <summary> /// 初始化 /// </summary> /// <param name="grid">要操作的ASPxGridView</param> /// <param name="fieldName">根据哪个字段分组合并,例如单据编号</param> /// <param name="columnNumber">使后N列不进行合并,例如N=4,即后4列数据不参与合并</param> /// <param name="header"> /// ASPxGridView多表头实现 /// 表头格式定义方法:相邻父列#分隔 上下级空格分隔 相邻子级用逗号分隔 /// </param> /// <param name="isOpenMutiHeader">是否启用多表头,默认关闭</param> /// <param name="isOpenMergeCell">是否启用合并单元格,默认关闭</param> public ASPxGridViewHelper(ASPxGridView grid, string fieldName, int[] notMergeNumbers, string header, bool isOpenMutiHeader, bool isOpenMergeCell) { this.grid = grid; this.fieldName = fieldName; this.header = header; this.isOpenMergeCell = isOpenMergeCell; this.isOpenMutiHeader = isOpenMutiHeader; this.notMergeNumbers = notMergeNumbers; Grid.HtmlRowCreated += new ASPxGridViewTableRowEventHandler(grid_HtmlRowCreated); Grid.HtmlDataCellPrepared += new ASPxGridViewTableDataCellEventHandler(grid_HtmlDataCellPrepared); Grid.HtmlCommandCellPrepared += new ASPxGridViewTableCommandCellEventHandler(grid_HtmlCommandCellPrepared); } #endregion #region 初始化准备 void grid_HtmlDataCellPrepared(object sender, ASPxGridViewTableDataCellEventArgs e) { if (cellRowSpans.ContainsKey(e.Cell)) { e.Cell.RowSpan = cellRowSpans[e.Cell]; } } void grid_HtmlCommandCellPrepared(object sender, ASPxGridViewTableCommandCellEventArgs e) { if (cellRowSpans.ContainsKey(e.Cell)) { e.Cell.RowSpan = cellRowSpans[e.Cell]; } } void grid_HtmlRowCreated(object sender, ASPxGridViewTableRowEventArgs e) { #region 多表头 if (isOpenMutiHeader) { ASPxGridView gv = sender as ASPxGridView; if (e.RowType == DevExpress.Web.ASPxGridView.GridViewRowType.Data && e.VisibleIndex == gv.PageIndex * gv.SettingsPager.PageSize) { SplitTableHeader(e.Row, header); } } #endregion #region 合并单元格 if (isOpenMergeCell) { bool isPrevColumnHasSameFormID = IsSameData(fieldName, e.VisibleIndex, e.VisibleIndex - 1); bool isNextColumnHasSameFormID = IsSameData(fieldName, e.VisibleIndex, e.VisibleIndex + 1); if (Grid.GetRowLevel(e.VisibleIndex) != Grid.GroupCount) return; List<int> num = new List<int>(); if (notMergeNumbers != null) num.AddRange(notMergeNumbers); for (int i = e.Row.Cells.Count - 1; i >= 0; i--) { if (!(num != null && num.Count > 0 && num.Contains(i))) { DevExpress.Web.ASPxGridView.Rendering.GridViewTableDataCell dataCell = e.Row.Cells[i] as DevExpress.Web.ASPxGridView.Rendering.GridViewTableDataCell; DevExpress.Web.ASPxGridView.Rendering.GridViewTableCommandCell commandCell = e.Row.Cells[i] as DevExpress.Web.ASPxGridView.Rendering.GridViewTableCommandCell; if (dataCell != null) { MergeCells(dataCell.DataColumn, e.VisibleIndex, dataCell, isNextColumnHasSameFormID, isPrevColumnHasSameFormID); } else if (commandCell != null) { MergeCells(commandCell.Column, e.VisibleIndex, commandCell, isNextColumnHasSameFormID, isPrevColumnHasSameFormID); } } } } #endregion } #endregion #region 合并单元格 void MergeCells(GridViewCommandColumn column, int visibleIndex, TableCell cell, bool isNextColumnHasSameFormID, bool isPrevColumnHasSameFormID) { if (isNextColumnHasSameFormID) { if (!commandCells.ContainsKey(column)) { commandCells[column] = cell; } } if (isPrevColumnHasSameFormID) { ((TableRow)cell.Parent).Cells.Remove(cell); if (commandCells.ContainsKey(column)) { TableCell commCell = commandCells[column]; if (!cellRowSpans.ContainsKey(commCell)) { cellRowSpans[commCell] = 1; } cellRowSpans[commCell] = cellRowSpans[commCell] + 1; } } if (!isNextColumnHasSameFormID) { commandCells.Remove(column); } } void MergeCells(GridViewDataColumn column, int visibleIndex, TableCell cell, bool isNextColumnHasSameFormID, bool isPrevColumnHasSameFormID) { bool isNextTheSame = IsNextColumnHasSameData(column, visibleIndex); if (isNextColumnHasSameFormID && isNextTheSame) { if (!mergedCells.ContainsKey(column)) { mergedCells[column] = cell; } } if (isPrevColumnHasSameFormID && IsPrevColumnHasSameData(column, visibleIndex)) { ((TableRow)cell.Parent).Cells.Remove(cell); if (mergedCells.ContainsKey(column)) { TableCell mergedCell = mergedCells[column]; if (!cellRowSpans.ContainsKey(mergedCell)) { cellRowSpans[mergedCell] = 1; } cellRowSpans[mergedCell] = cellRowSpans[mergedCell] + 1; } } if (!isNextColumnHasSameFormID) { mergedCells.Remove(column); } } bool IsNextColumnHasSameData(GridViewDataColumn column, int visibleIndex) { //is it the last visible row if (visibleIndex >= Grid.VisibleStartIndex + Grid.VisibleRowCount - 1) return false; return IsSameData(column.FieldName, visibleIndex, visibleIndex + 1); } bool IsPrevColumnHasSameData(GridViewDataColumn column, int visibleIndex) { ASPxGridView grid = column.Grid; //is it the first visible row if (visibleIndex <= Grid.VisibleStartIndex) return false; return IsSameData(column.FieldName, visibleIndex, visibleIndex - 1); } bool IsSameData(string fieldName, int visibleIndex1, int visibleIndex2) { // is it a group row? if (Grid.GetRowLevel(visibleIndex2) != Grid.GroupCount) return false; return object.Equals(Grid.GetRowValues(visibleIndex1, fieldName), Grid.GetRowValues(visibleIndex2, fieldName)); } #endregion #region 多表头 /// <summary> /// 重写表头 /// </summary> /// <param name="targetHeader">目标表头</param> /// <param name="newHeaderNames">新表头</param> /// <remarks> /// 等级#级别#上期结存 件数,重量,比例#本期调入 收购调入 件数,重量,比例#本期发出 车间投料 件数,重量, /// 比例#本期发出 产品外销百分比 件数,重量,比例#平均值 /// </remarks> void SplitTableHeader(TableRow targetHeader, string newHeaderNames) { Table table = targetHeader.Parent as Table; table.Rows.RemoveAt(0); table.CssClass = "dxgvTable_Office2003_Blue"; int row = GetRowCount(newHeaderNames); int col = GetColCount(newHeaderNames); string[,] nameList = ConvertList(newHeaderNames, row, col); int RowSpan = 0; int ColSpan = 0; for (int k = 0; k < row; k++) { TableRow trow = new TableRow(); trow.Height = 20; string LastFName = ""; for (int i = 0; i < col; i++) { TableCell cell = new TableCell(); if (LastFName == nameList[i, k] && k != row - 1) { LastFName = nameList[i, k]; continue; } else { LastFName = nameList[i, k]; } int bFlag = IsVisible(nameList, k, i, LastFName); switch (bFlag) { case 0: break; case 1: RowSpan = GetSpanRowCount(nameList, row, k, i); ColSpan = GetSpanColCount(nameList, row, col, k, i); cell = new TableCell(); cell.RowSpan = RowSpan; cell.ColumnSpan = ColSpan; cell.CssClass = "dxgvHeader_Office2003_Blue"; cell.Text = LastFName; cell.BorderStyle = BorderStyle.Solid; cell.BorderWidth = Unit.Pixel(0); cell.Style.Add(HtmlTextWriterStyle.TextAlign, "center"); cell.Style.Add(HtmlTextWriterStyle.BorderCollapse, "collapse"); cell.Style.Add(HtmlTextWriterStyle.BorderCollapse, "separate"); cell.Style["BORDER-RIGHT-WIDTH"] = "1px"; cell.Style["BORDER-BOTTOM-WIDTH"] = "1px"; trow.Cells.Add(cell); break; case -1: string[] EndColName = LastFName.Split(new char[] { ',' }); foreach (string eName in EndColName) { cell = new TableCell(); cell.Text = eName; cell.BorderStyle = BorderStyle.Solid; cell.BorderWidth = Unit.Pixel(0); cell.CssClass = "dxgvHeader_Office2003_Blue"; cell.Style.Add(HtmlTextWriterStyle.TextAlign, "center"); cell.Style.Add(HtmlTextWriterStyle.BorderCollapse, "collapse"); cell.Style.Add(HtmlTextWriterStyle.BorderCollapse, "separate"); cell.Style["BORDER-RIGHT-WIDTH"] = "1px"; cell.Style["BORDER-BOTTOM-WIDTH"] = "1px"; trow.Cells.Add(cell); } break; } } if (k != row - 1) {//不是起始行,加入新行标签 //cell.Text = cell.Text + "</th></tr><tr>"; } table.Rows.AddAt(k, trow); } } /**/ /// <summary> /// 如果上一行已经输出和当前内容相同的列头,则不显示 /// </summary> /// <param name="ColumnList">表头集合</param> /// <param name="rowIndex">行索引</param> /// <param name="colIndex">列索引</param> /// <returns>1:显示,-1:含','分隔符,0:不显示</returns> private int IsVisible(string[,] ColumnList, int rowIndex, int colIndex, string CurrName) { if (rowIndex != 0) { if (ColumnList[colIndex, rowIndex - 1] == CurrName) { return 0; } else { if (ColumnList[colIndex, rowIndex].Contains(",")) { return -1; } else { return 1; } } } return 1; } /**/ /// <summary> /// 取得和当前索引行及列对应的下级的内容所跨的行数 /// </summary> /// <param name="ColumnList">表头集合</param> /// <param name="row">行数</param> /// <param name="rowIndex">行索引</param> /// <param name="colIndex">列索引</param> /// <returns>行数</returns> private int GetSpanRowCount(string[,] ColumnList, int row, int rowIndex, int colIndex) { string LastName = ""; int RowSpan = 1; for (int k = rowIndex; k < row; k++) { if (ColumnList[colIndex, k] == LastName) { RowSpan++; } else { LastName = ColumnList[colIndex, k]; } } return RowSpan; } /**/ /// <summary> /// 取得和当前索引行及列对应的下级的内容所跨的列数 /// </summary> /// <param name="ColumnList">表头集合</param> /// <param name="row">行数</param> /// <param name="col">列数</param> /// <param name="rowIndex">行索引</param> /// <param name="colIndex">列索引</param> /// <returns>列数</returns> private int GetSpanColCount(string[,] ColumnList, int row, int col, int rowIndex, int colIndex) { string LastName = ColumnList[colIndex, rowIndex]; int ColSpan = ColumnList[colIndex, row - 1].Split(new char[] { ',' }).Length; ColSpan = ColSpan == 1 ? 0 : ColSpan; for (int i = colIndex + 1; i < col; i++) { if (ColumnList[i, rowIndex] == LastName) { ColSpan += ColumnList[i, row - 1].Split(new char[] { ',' }).Length; } else { LastName = ColumnList[i, rowIndex]; break; } } return ColSpan; } /**/ /// <summary> /// 将已定义的表头保存到数组 /// </summary> /// <param name="newHeaders">新表头</param> /// <param name="row">行数</param> /// <param name="col">列数</param> /// <returns>表头数组</returns> private string[,] ConvertList(string newHeaders, int row, int col) { string[] ColumnNames = newHeaders.Split(new char[] { '#' }); string[,] news = new string[col, row]; string Name = ""; for (int i = 0; i < col; i++) { string[] CurrColNames = ColumnNames[i].ToString().Split(new char[] { ' ' }); for (int k = 0; k < row; k++) { if (CurrColNames.Length - 1 >= k) { if (CurrColNames[k].Contains(",")) { if (CurrColNames.Length != row) { if (Name == "") { news[i, k] = news[i, k - 1]; Name = CurrColNames[k].ToString(); } else { news[i, k + 1] = Name; Name = ""; } } else { news[i, k] = CurrColNames[k].ToString(); } } else { news[i, k] = CurrColNames[k].ToString(); } } else { if (Name == "") { news[i, k] = news[i, k - 1]; } else { news[i, k] = Name; Name = ""; } } } } return news; } /**/ /// <summary> /// 取得复合表头的行数 /// </summary> /// <param name="newHeaders">新表头</param> /// <returns>行数</returns> private int GetRowCount(string newHeaders) { string[] ColumnNames = newHeaders.Split(new char[] { '#' }); int Count = 0; foreach (string name in ColumnNames) { int TempCount = name.Split(new char[] { ' ' }).Length; if (TempCount > Count) Count = TempCount; } return Count; } /**/ /// <summary> /// 取得复合表头的列数 /// </summary> /// <param name="newHeaders">新表头</param> /// <returns>列数</returns> private int GetColCount(string newHeaders) { return newHeaders.Split(new char[] { '#' }).Length; } #endregion #region ASPxGridView列操作 //#region 创建GridViewDataColumn列 //public static GridViewDataColumn CreateDataColumn(string caption, string fieldName, int width, bool visible, int visibleIndex, DevExpress.Data.ColumnSortOrder sortOrder, ColumnFilterMode columnFilterMode, DevExpress.Web.ASPxClasses.DefaultBoolean autoFilter, DevExpress.Web.ASPxClasses.DefaultBoolean headerFilter) //{ // GridViewDataTextColumn column = new GridViewDataTextColumn(); // column.Caption = caption; // column.FieldName = fieldName; // if (width != 0) column.Width = width; // column.Visible = visible; // column.VisibleIndex = visibleIndex; // column.SortOrder = sortOrder; // column.Settings.AllowAutoFilter = autoFilter; // column.Settings.AllowHeaderFilter = headerFilter; // column.Settings.FilterMode = columnFilterMode; // return column; //} //#endregion #region 显示隐藏列 public void ChangeColumsDisplay(string[] displayFields, bool display) { if (displayFields != null && displayFields.Length > 0) { foreach (string item in displayFields) { Grid.Columns[item].Visible = display; } } } #endregion #region 改变列的显示索引 public void ChangeColumnsVisibleIndex(string[] fields, int[] newVisibleIndex) { if (fields != null && fields.Length > 0) { for (int i = 0; i < fields.Length; i++) { Grid.Columns[fields[i]].VisibleIndex = newVisibleIndex[i]; } } } #endregion #region 改变列标题 public void ChangeColumnsCaption(string[] fields, string[] newCaption) { if (fields != null && fields.Length > 0) { for (int i = 0; i < fields.Length; i++) { Grid.Columns[fields[i]].Caption = newCaption[i]; } } } #endregion #endregion } }
使用举例:根据不同的条件显示自定义的多表头、字段及合并单元格
protected void Page_Load(object sender, EventArgs e) { InitGrid(); InitGridDisplayColumns();//此方法在GridView绑定数据之前扔需执行 }
private void InitGrid() { string header = "选择#序号#设备位号#设备名称#检修<br/>类别#检修内容 序号,内容#主要备件及材料 名称,规格,材质,数量,单位#施工单位#项目负责人 施工单位,生产车间,配合部门#完成情况 开工,完工#计划<br/>检修<br/>时间#备注"; string fieldName = "JXBH"; bool isOpenMergeCell = true; bool isOpenMutiHeader = true; int[] num = null; switch (XMIndex) { case 1://工艺 header = "选择#序号#工段#工艺项目内容 序号,内容#施工单位#项目负责人 生产车间,配合部门#备注"; break; case 2://容器 header = "选择#序号#容器编号#容器名称#类别#内径#材质#壁厚#长度#操作压力#操作温度#介质#安全状况等级#到期检验日期#计划安排检验时间#重点检验部位#备注"; isOpenMergeCell = false; break; case 3://管道 header = "选择#序号#管道编号#管线号#管道起点#管道止点#公称直径#公称壁厚#累计长度#工作压力#工作温度#材质#级别#介质#近期检验日期#下次检验日期#安全状况等级#重点检验部位#备注"; isOpenMergeCell = false; break; case 5://防腐保温 header = "选择#序号#位号#名称#工段#具体内容 序号,内容,数量#备注"; break; default: num = new int[] { 7, 8, 9, 10, 11 }; break; } ASPxGridViewHelper helper = new ASPxGridViewHelper(this.GV_JH, fieldName, num, header, isOpenMutiHeader, isOpenMergeCell); } private void InitGridDisplayColumns() { string[] hidenFields = null; int[] newNums = new int[] { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; switch (XMIndex) { case 1://工艺 hidenFields = new string[] { "SBWH", "JXLB", "BJBM", "BJMC", "BJGG", "BJTH", "BJCZ", "BJSL", "SLDW", "SGDWFZR", "JHKG", "JHWG", "JHJXSJ" }; break; case 2://容器 hidenFields = new string[] { "JXLB", "JXNRH", "JXNR", "SCCJFZR", "JHJXSJ" }; newNums = new int[] { 2, 3, 4, 5, 6, 7, 10, 11, 8, 9, 12, 13, 14, 15, 16, 19, 17, 18, 20, 21 }; break; case 3://管道 hidenFields = new string[] { "JXLB", "JXNRH", "JXNR" }; newNums = new int[] { 3, 2, 4, 5, 6, 7, 9, 11, 10, 14, 12, 13, 16, 19, 8, 20, 17, 18, 15, 21 }; break; case 5://防腐保温 hidenFields = new string[] { "JXLB", "BJBM", "BJGG", "BJTH", "BJCZ", "SLDW", "SGDW", "SGDWFZR", "SCCJFZR", "PHBMFZR", "JHKG", "JHWG", "JHJXSJ" }; newNums = new int[] { 2, 3, 8, 5, 6, 7, 4, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; break; default: hidenFields = new string[] { "BJBM", "BJTH" }; break; } ASPxGridViewHelper helper = new ASPxGridViewHelper(this.GV_JH); string[] fields = new string[] { "SBWH", "SBMC", "JXLB", "JXNRH", "JXNR", "BJBM", "BJMC", "BJGG", "BJTH", "BJCZ", "BJSL", "SLDW", "SGDW", "SGDWFZR", "SCCJFZR", "PHBMFZR", "JHKG", "JHWG", "JHJXSJ", "BZ" }; helper.ChangeColumsDisplay(fields, true); helper.ChangeColumnsVisibleIndex(fields, newNums); helper.ChangeColumsDisplay(hidenFields, false); }
部分代码来源互联网
实现效果图: