ASPxGridView
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
}
}
使用举例:根据不同的条件显示自定义的多表头、字段及合并单元格
[csharp] view plaincopy
protected void Page_Load(object sender, EventArgs e)
{
InitGrid();
InitGridDisplayColumns();//此方法在GridView绑定数据之前扔需执行
}
[csharp] view plaincopy
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);
}