在 WinForms 專案中,若需將資料匯出為格式豐富的 Excel 檔案(含樣式、公式、分頁設定),Microsoft.Office.Interop.Excel 仍是最直觀、功能最完整的選擇。本文提供一個完整的「另存為」實作範例,涵蓋資料寫入、儲存格格式化、邊框樣式、頁面設定與儲存對話框等實務技巧。
private void btnSaveAsData_Click(object sender, EventArgs e)
{
// 1. 建立 Excel 應用程式與活頁簿
Excel.Application xlsApp = new Excel.Application();
Excel._Workbook xlsBook = xlsApp.Workbooks.Add(Excel.XlWBATemplate.xlWBATWorksheet);
Excel._Worksheet xlsSheet = (Excel._Worksheet)xlsBook.Worksheets[1];
xlsSheet.Activate();
// 2. 設定標題與資料來源
xlsApp.Caption = lblDMMC.Text + "斷面實測成果表 - 另存為";
DataTable myDT1 = GetDataTable(...); // 取得主資料
DataTable myDT2 = GetDataTable(...); // 取得輔助資料
// 3. 寫入表頭、資料列、特殊標記(▲/▼)
// ... 迴圈寫入 xlsSheet.Cells[row, col] ...
// 4. 進階格式化:欄寬、行高、字型、對齊、邊框、數值格式
xlsSheet.Columns.ColumnWidth = 9;
xlsSheet.Rows.RowHeight = 18;
xlsSheet.Cells.Font.Name = "新細明體"; // 建議使用系統通用字型
xlsSheet.Cells.Font.Size = 10;
// 設定標題列粗體、特定儲存格底線、數值格式(##### / #####.0)等
// 5. 列印設定(若需列印)
xlsSheet.PageSetup.Orientation = Excel.XlPageOrientation.xlLandscape;
xlsSheet.PageSetup.PaperSize = Excel.XlPaperSize.xlPaperA4;
xlsSheet.PageSetup.CenterHorizontally = true;
// 設定邊距、標題列重複列印等
// 6. 彈出「另存新檔」對話框並儲存
string fileName = xlsApp.GetSaveAsFilename(
"斷面實測成果表.xls",
"Excel檔案 (*.xls), *.xls",
1,
"斷面實測成果表"
).ToString().Trim();
if (!string.IsNullOrEmpty(fileName) && fileName != "False")
{
xlsSheet.SaveAs(fileName, Excel.XlFileFormat.xlExcel9795,
Type.Missing, Type.Missing, false, false,
Excel.XlSaveAsAccessMode.xlNoChange,
Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
}
// 7. **關鍵:正確釋放 COM 物件,避免 Excel 殭屍進程**
xlsBook.Saved = true;
xlsBook.Close();
xlsApp.Quit();
ReleaseComObject(xlsSheet);
ReleaseComObject(xlsBook);
ReleaseComObject(xlsApp);
GC.Collect();
GC.WaitForPendingFinalizers();
}
每一個 Excel.Range、Worksheet、Workbook、Application 都屬於 COM 物件,**必須顯式呼叫 Marshal.ReleaseComObject()**,否則 Excel 進程將殘留在背景。建議封裝輔助方法:
private void ReleaseComObject(object obj)
{
if (obj != null)
{
try { Marshal.ReleaseComObject(obj); }
catch { }
finally { obj = null; }
}
}
錯誤: xlsApp.Workbooks.Add().Worksheets[1](中間產生的 Workbooks 未釋放)
正確: 分層宣告變數並逐一釋放,如範例所示。
逐格寫入 Cells[i, j] = value 極慢。大量資料請改用陣列一次寫入:
object[,] data = new object[rowCount, colCount];
// 填入陣列...
xlsSheet.get_Range("A1").Resize[rowCount, colCount].Value2 = data;
xlExcel9795 產生 .xls (BIFF8) 格式,若需 .xlsx 請改用 xlOpenXMLWorkbook (51)。Interop 雖功能強大,但部署門檻高、效能較差、記憶體管理繁瑣。現代專案建議優先評估 ClosedXML(支援 .xlsx、語法優雅、無 Office 相依),僅在必須使用 Excel 獨有功能(如巨集、複雜圖表、列印預覽)時才採用 Interop。