[GridView]datarow與headerrow合併儲存格

  • 13440
  • 0
  • 2008-12-29

[GridView]datarow與headerrow合併儲存格

對User來說,GridView跟Table,在跟他們手上的文件資料比較起來,是沒有啥差別的。

e化,就是要樣子長的一模一樣,所以GridView還蠻常遇到要以「合併儲存格」來呈現資料的需求。

其實上網找就有很多例子,解法都大同小異,只是有的是硬尻,有的是包得漂亮一點。

這邊提供個範例,好用就在於只要改需要合併的相關參數馬上就能用。

前提:

  1. GridView會喪失排序功能。
  2. DataRow的HighLight功能會變很醜。
  3. 當GridView沒有資料的時候,這邊沒有額外處理。
  4. 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()去處理)


或許您會對下列培訓課程感興趣:

  1. 2020/09/26(六)~2020/09/27(日):演化式設計:測試驅動開發與持續重構(台北)
  2. 2020/11/07(六):【針對遺留代碼加入單元測試的藝術】(台北)
  3. 2020/11/08(日):【極速開發+】(台北)

想收到第一手公開培訓課程資訊,或想詢問企業內訓、顧問、教練、諮詢服務的,請洽 Facebook 粉絲專頁:91敏捷開發之路