[GridView]datarow與headerrow合併儲存格
對User來說,GridView跟Table,在跟他們手上的文件資料比較起來,是沒有啥差別的。
e化,就是要樣子長的一模一樣,所以GridView還蠻常遇到要以「合併儲存格」來呈現資料的需求。
其實上網找就有很多例子,解法都大同小異,只是有的是硬尻,有的是包得漂亮一點。
這邊提供個範例,好用就在於只要改需要合併的相關參數馬上就能用。
前提:
- GridView會喪失排序功能。
- DataRow的HighLight功能會變很醜。
- 當GridView沒有資料的時候,這邊沒有額外處理。
- pager的筆數可能不是user想要的。(排序後的資料集合RowSpan後,「一對多」的情況,對GridView而言,筆數為「多」筆。對User而言,筆數為「一」筆。即使Order後,仍會有同一資料跨頁沒合併的問題。
適用情況:單純呈現資料。
首先是針對DataRow做RowSpan的部分:
第一個method是針對資料裡的「單欄」做RowSpan。
/// <summary>
/// 將gridView中相鄰的row之欄位值相同時作跨列合併
/// </summary>
/// <param name="gridView">欲進行合併之GridView控制項</param>
/// <param name="cellIndex">欲進行跨列合併之欄位index</param>
protected void MergeRows(GridView gridView,int cellIndex)
{
int rowNum = -1;
foreach (GridViewRow gvrow in gridView.Rows)
{
if (gvrow.RowIndex > 0)
{
if (gvrow.Cells[cellIndex].Text == gridView.Rows[gvrow.RowIndex -1].Cells[cellIndex].Text)
{
if (rowNum == -1)
{
rowNum = gvrow.RowIndex - 1;
gridView.Rows[rowNum].Cells[cellIndex].RowSpan += 1;
}
gridView.Rows[rowNum].Cells[cellIndex].RowSpan += 1;
gvrow.Cells[cellIndex].Visible = false;
}
else
rowNum = -1;
}
}
}
第二個method是針對資料裡的「多欄」做RowSpan。
/// <summary>
/// 將gridView中相鄰的row之欄位值相同時作跨列合併
/// </summary>
/// <param name="gridView">欲進行合併之GridView控制項</param>
/// <param name="cellIndex[]">欲進行跨列合併之欄位index陣列。ex:{3,5},欄位index為3及5的欄位皆進行跨列合併</param>
protected void MergeRows(GridView gridView, int[] cellIndex)
{
int[] rowNum = new int[cellIndex.Length];
int rowNumIndex ;
for (int i = 0; i < cellIndex.Length; i++)
{
rowNum[i] = -1;
}
foreach (GridViewRow gvrow in gridView.Rows)
{
if (gvrow.RowIndex > 0)
{
rowNumIndex = 0;
foreach (int cindex in cellIndex)
{
if (gvrow.Cells[cindex].Text == gridView.Rows[gvrow.RowIndex - 1].Cells[cindex].Text)
{
if (rowNum[rowNumIndex] == -1)
{
rowNum[rowNumIndex] = gvrow.RowIndex - 1;
gridView.Rows[rowNum[rowNumIndex]].Cells[cindex].RowSpan += 1;
}
gridView.Rows[rowNum[rowNumIndex]].Cells[cindex].RowSpan += 1;
gvrow.Cells[cindex].Visible = false;
}
else
rowNum[rowNumIndex] = -1;
rowNumIndex++;
}
}
}
}
使用方式,只要在Grid.DataBind()後,呼叫MergeRows()即可。
protected void Page_Load(object sender, EventArgs e)
{
//MergeRows(GridView1, 0);
//MergeRows(GridView1, 1);
MergeRows(GridView1,new int[] {0,1,3,4 });
}
再來是針對GridView的Header做ColumnSpan與RowSpan。
/// <summary>
/// 處理gridView之header需有2列,且會跨欄及跨列合併之需求
/// 缺點:header的排序功能會被清除
/// </summary>
/// <param name="gridView">欲進行header處理之GridView控制項</param>
/// <param name="cellIndex">欲進行跨欄合併之欄位index</param>
/// <param name="mergeHeaderText">跨欄合併之欄位的文字</param>
/// <param name="mergeNum">欲進行跨欄合併之欄位數</param>
protected void MergeHeader(GridView gridView, int cellIndex, string mergeHeaderText,int mergeNum)
{
GridViewRow headRow = new GridViewRow(0, 0, DataControlRowType.Header, DataControlRowState.Insert);
TableCell tCell = null;
for (int i = 0; i < gridView.Columns.Count; i++)
{
tCell = new TableCell();
if (i != cellIndex)
{
tCell.RowSpan = 2;
tCell.Text = GridView1.Columns[i].HeaderText;
}
else
{
tCell.ColumnSpan = mergeNum;
tCell.HorizontalAlign = HorizontalAlign.Center;
tCell.Text = mergeHeaderText;
i = i + mergeNum - 1;
}
headRow.Cells.Add(tCell);
}
GridView1.Controls[0].Controls.Add(headRow);
headRow = new GridViewRow(0, 0, DataControlRowType.Header, DataControlRowState.Insert);
for (int i = 0; i < mergeNum; i++)
{
tCell = new TableCell();
tCell.Text = GridView1.Columns[cellIndex + i].HeaderText;
headRow.Cells.Add(tCell);
}
GridView1.Controls[0].Controls.Add(headRow);
}
}
接著在Gird的RowCreated事件,呼叫MergeHeader()即可。
protected void GridView1_RowCreated(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.Header)
{
e.Row.Cells.Clear();
MergeHeader(GridView1,4, "合併欄位文字",3);
}
}
注意:RowCreated()沒資料的時候不會觸發。(通常變形的作法就是在PreRender()去處理)
blog 與課程更新內容,請前往新站位置:http://tdd.best/