首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

ASP.NET GridView 與 DataGrid 相同列合併儲存格完整實作 (含模板欄位)

     編輯:ASP.NET 基礎

核心邏輯

合併儲存格原理:資料預先分組排序 → 遍歷列 → 相同值設 RowSpan 遞增、隱藏重複儲存格。必須在 DataBound 事件中執行,確保資料已繫結完成。

一、一般欄位合併 (BoundField 等)

GridView 版本

public static void MergeCells(GridView gv, int columnIndex)
{
    if (gv.Rows.Count == 0) return;

    string lastValue = gv.Rows[0].Cells[columnIndex].Text;
    gv.Rows[0].Cells[columnIndex].RowSpan = 1;
    int lastRowIndex = 0;

    for (int i = 1; i < gv.Rows.Count; i++)
    {
        string currentValue = gv.Rows[i].Cells[columnIndex].Text;
        if (currentValue == lastValue)
        {
            gv.Rows[i].Cells[columnIndex].Visible = false; // 隱藏重複
            gv.Rows[lastRowIndex].Cells[columnIndex].RowSpan++;
        }
        else
        {
            lastValue = currentValue;
            lastRowIndex = i;
            gv.Rows[i].Cells[columnIndex].RowSpan = 1;
        }
    }
}

DataGrid 版本

public static void MergeCells(DataGrid dg, int columnIndex)
{
    if (dg.Items.Count == 0) return;

    string lastValue = dg.Items[0].Cells[columnIndex].Text;
    dg.Items[0].Cells[columnIndex].RowSpan = 1;
    int lastRowIndex = 0;

    for (int i = 1; i < dg.Items.Count; i++)
    {
        string currentValue = dg.Items[i].Cells[columnIndex].Text;
        if (currentValue == lastValue)
        {
            dg.Items[i].Cells[columnIndex].Visible = false;
            dg.Items[lastRowIndex].Cells[columnIndex].RowSpan++;
        }
        else
        {
            lastValue = currentValue;
            lastRowIndex = i;
            dg.Items[i].Cells[columnIndex].RowSpan = 1;
        }
    }
}

二、模板欄位合併

需透過 FindControl 取得控制項實例讀取值:

public static void MergeTemplateCells(GridView gv, int columnIndex, string controlId)
{
    if (gv.Rows.Count == 0) return;

    var firstCtrl = gv.Rows[0].Cells[columnIndex].FindControl(controlId) as Label;
    string lastValue = firstCtrl?.Text ?? "";
    gv.Rows[0].Cells[columnIndex].RowSpan = 1;
    int lastRowIndex = 0;

    for (int i = 1; i < gv.Rows.Count; i++)
    {
        var ctrl = gv.Rows[i].Cells[columnIndex].FindControl(controlId) as Label;
        string currentValue = ctrl?.Text ?? "";
        
        if (currentValue == lastValue)
        {
            gv.Rows[i].Cells[columnIndex].Visible = false;
            gv.Rows[lastRowIndex].Cells[columnIndex].RowSpan++;
        }
        else
        {
            lastValue = currentValue;
            lastRowIndex = i;
            gv.Rows[i].Cells[columnIndex].RowSpan = 1;
        }
    }
}

三、頁面呼叫時機

protected void GridView1_DataBound(object sender, EventArgs e)
{
    // 一般欄位:第 0、2 欄合併
    MergeCells(GridView1, 0);
    MergeCells(GridView1, 2);
    
    // 模板欄位:第 1 欄,控制項 ID 為 "lblCategory"
    MergeTemplateCells(GridView1, 1, "lblCategory");
}

四、固定欄寬顯示 (防止內容撐開版面)

protected void GridView1_RowCreated(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.Header)
    {
        foreach (TableCell cell in e.Row.Cells)
        {
            cell.Width = Unit.Pixel(120);
            cell.Wrap = false; // 禁止換行
        }
    }
}

// DataGrid 對應寫法
protected void DataGrid1_ItemCreated(object sender, DataGridItemEventArgs e)
{
    if (e.Item.ItemType == ListItemType.Header)
    {
        foreach (TableCell cell in e.Item.Cells)
        {
            cell.Width = Unit.Pixel(50);
            cell.Wrap = false;
        }
    }
}

五、完整 ASPX 範例

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" 
    OnDataBound="GridView1_DataBound" OnRowCreated="GridView1_RowCreated">
    <Columns>
        <asp:BoundField DataField="Department" HeaderText="部門" />
        <asp:TemplateField HeaderText="類別">
            <ItemTemplate>
                <asp:Label ID="lblCategory" runat="server" Text='<%# Eval("Category") %>' />
            </ItemTemplate>
        </asp:TemplateField>
        <asp:BoundField DataField="Status" HeaderText="狀態" />
        <asp:BoundField DataField="Amount" HeaderText="金額" />
    </Columns>
</asp:GridView>

六、注意事項與限制

限制說明解決方案
資料必須預先排序相同值必須連續才能合併SQL `ORDER BY` 或 `DataView.Sort`
分頁會中斷合併每頁獨立計算 RowSpan不分頁或自訂跨頁合併邏輯
RowSpan 跨越隱藏列隱藏列仍佔據 DOM 空間正常現象,CSS 控制視覺即可
編輯模式衝突編輯時合併邏輯可能錯亂編輯模式暫停合併
巢狀 GridView內層合併不影響外層分別呼叫合併方法

七、現代替代方案

若專案允許,建議改用前端元件庫:

  • jQuery DataTables:內建 `rowGroup` 擴充套件支援合併
  • Bootstrap Table:`data-rowspan` 屬性
  • AG Grid / DevExtreme:企業級 Grid 完整支援儲存格合併
  • Blazor / Razor Components:自訂 Render 邏輯更靈活

總結

透過 DataBound 事件遍歷列、比對值、設定 RowSpan 與 Visible=false,即可實作 GridView/DataGrid 儲存格合併。關鍵在於資料預先排序與正確取值方式 (一般欄位用 `.Text`,模板欄位用 `FindControl`)。現代專案建議前移合併邏輯至前端元件,後端僅負責輸出結構化資料。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved