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);
}