匯出報表時,若多欄位連續列具有相同值(如部門、類別、區域),需自動合併儲存格以提升可讀性,如下圖所示:

逐欄掃描,比較當前列與下一列在「從第一欄到當前欄」的組合值是否相同,相同則累加合併計數,不同則執行合併並重置計數。
using Excel = Microsoft.Office.Interop.Excel;
public class ExcelMerger
{
private Excel.Worksheet _worksheet;
public ExcelMerger(Excel.Worksheet worksheet)
{
_worksheet = worksheet;
}
///
/// 合併指定範圍內連續相同值的儲存格
///
/// 工作表索引 (1-based)
/// 起始列索引 (1-based)
/// 起始欄索引 (1-based)
/// 要處理的列數
/// 要處理的欄數
public void MergeContinuousCells(int sheetIndex, int startRow, int startCol, int rowCount, int colCount)
{
if (rowCount < 1 || colCount < 1) return;
for (int colOffset = 0; colOffset < colCount; colOffset++)
{
int markRow = 0; // 當前合併區塊起始列(相對偏移)
int mergeCount = 1; // 連續相同列數
for (int rowOffset = 0; rowOffset < rowCount; rowOffset++)
{
bool isLastRow = (rowOffset == rowCount - 1);
// 建立「從第 0 欄到當前欄」的組合鍵值
string currentKey = BuildCompositeKey(startRow + rowOffset, startCol, colOffset);
string nextKey = isLastRow ? null : BuildCompositeKey(startRow + rowOffset + 1, startCol, colOffset);
if (!isLastRow && currentKey == nextKey)
{
mergeCount++;
}
else
{
// 執行合併:從 markRow 開始,共 mergeCount 列
if (mergeCount > 1)
{
int actualStartRow = startRow + markRow;
int actualEndRow = actualStartRow + mergeCount - 1;
int actualCol = startCol + colOffset;
MergeRange(actualStartRow, actualCol, actualEndRow, actualCol);
}
// 重置下一區塊
markRow = rowOffset + 1;
mergeCount = 1;
}
}
}
}
private string BuildCompositeKey(int row, int startCol, int endColOffset)
{
var parts = new List();
for (int c = 0; c <= endColOffset; c++)
{
var cell = (Excel.Range)_worksheet.Cells[row, startCol + c];
// 取得合併區域左上角儲存格的值(避免重複讀取已合併儲存格)
var topLeft = (Excel.Range)cell.MergeArea.Item[1, 1];
parts.Add(topLeft.Text?.ToString() ?? "");
}
return string.Join("|", parts);
}
private void MergeRange(int startRow, int startCol, int endRow, int endCol)
{
var range = _worksheet.Range[
_worksheet.Cells[startRow, startCol],
_worksheet.Cells[endRow, endCol]
];
range.Merge();
range.VerticalAlignment = Excel.XlVAlign.xlVAlignCenter;
range.HorizontalAlignment = Excel.XlHAlign.xlHAlignCenter;
}
}
var app = new Excel.Application();
var wb = app.Workbooks.Open(templatePath);
var ws = (Excel.Worksheet)wb.Worksheets[1];
// 假設資料從第 2 列開始,共 100 列,5 欄 (A-E),要合併前 3 欄 (A-C)
var merger = new ExcelMerger(ws);
merger.MergeContinuousCells(1, 2, 1, 100, 3);
wb.SaveAs(outputPath);
wb.Close();
app.Quit();
// 釋放 COM 物件...
| 分隔多欄值,確保「部門=A, 類別=X」不會誤判為「部門=AX, 類別=空」MergeArea.Item[1,1],避免重複讀取已合併區域導致邏輯錯誤object[,] data = range.Value,記憶體中計算合併區間,再一次性呼叫 Merge()Microsoft.Office.Interop.Excel使用 ClosedXML 或 EPPlus 可在無 Office 環境下實現相同功能,語法更簡潔:
// ClosedXML 範例
var ws = wb.Worksheet(1);
var range = ws.Range(2, 1, 101, 3); // A2:C101
range.MergeSameCells(); // 擴充方法一鍵完成