
如何在 C# 中将 GridView 导出到 Excel 并保留格式
在将 GridView 数据导出到 Excel 时,保留颜色、字体、交替行背景色和边框,是几乎所有数据驱动型 ASP.NET 或 Windows Forms 应用程序中都会出现的需求。 传统方法——使用StringWriter将控件呈现为HTML——生成的文件在Excel中带有格式警告,并且无声失败。 IronXL 通过完全使用 C# 生成原生 XLSX 文件来解决这一问题,且不依赖 Microsoft Office,让您能够精确控制每个单元格的样式。
如何在.NET项目中安装库?
在编写任何导出代码之前,请先从 NuGet 安装 IronXL。 打开软件包管理器控制台并运行:
IronXL 支持 .NET 8、.NET 9 和 .NET 10,以及 .NET Framework 4.6.2 及更高版本。 安装完成后,将以下using指令添加到执行Excel操作的任何文件中:
using IronXL;
using IronXL.Styles;Imports IronXL
Imports IronXL.Styles无需额外的运行时环境或 Office 互操作支持。 该库生成的原生 XLSX 二进制文件可在 Microsoft Excel、LibreOffice Calc 和 Google 表格中完美打开。
如何将 Windows Forms 的 DataGridView 连同单元格格式一起导出到 Excel?
Windows Forms应用程序使用GridView。 导出模式在两种情况下相同:从行和单元格中提取值,创建一个IronXL工作簿,应用样式,然后保存或流出结果。
最可靠的方法是将控件的DataTable,以避免遍历可视行,这些行可能已被过滤或分页:
using IronXL;
using IronXL.Styles;
using System;
using System.Data;
using System.IO;
using System.Windows.Forms;
DataTable dt = (DataTable)dataGridView1.DataSource;
WorkBook workBook = WorkBook.Create(ExcelFileFormat.XLSX);
WorkSheet sheet = workBook.DefaultWorkSheet;
// Header row -- bold, blue background, white text
for (int col = 0; col < dt.Columns.Count; col++)
{
sheet.SetCellValue(0, col, dt.Columns[col].ColumnName);
var cell = sheet.GetCellAt(0, col);
cell.Style.Font.Bold = true;
cell.Style.SetBackgroundColor("#4472C4");
cell.Style.Font.Color = "#FFFFFF";
cell.Style.BottomBorder.Type = BorderType.Thin;
}
// Data rows -- alternating row color
for (int row = 0; row < dt.Rows.Count; row++)
{
for (int col = 0; col < dt.Columns.Count; col++)
{
string value = dt.Rows[row][col]?.ToString() ?? string.Empty;
sheet.SetCellValue(row + 1, col, value);
var cell = sheet.GetCellAt(row + 1, col);
cell.Style.SetBackgroundColor(row % 2 == 0 ? "#D6DCE5" : "#FFFFFF");
cell.Style.BottomBorder.Type = BorderType.Thin;
}
}
// Save via dialog
using var saveDialog = new SaveFileDialog
{
Filter = "Excel Files|*.xlsx",
FileName = "GridViewExport.xlsx"
};
if (saveDialog.ShowDialog() == DialogResult.OK)
{
workBook.SaveAs(saveDialog.FileName);
MessageBox.Show("Export successful.", "Export",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}Imports IronXL
Imports IronXL.Styles
Imports System
Imports System.Data
Imports System.IO
Imports System.Windows.Forms
Dim dt As DataTable = DirectCast(dataGridView1.DataSource, DataTable)
Dim workBook As WorkBook = WorkBook.Create(ExcelFileFormat.XLSX)
Dim sheet As WorkSheet = workBook.DefaultWorkSheet
' Header row -- bold, blue background, white text
For col As Integer = 0 To dt.Columns.Count - 1
sheet.SetCellValue(0, col, dt.Columns(col).ColumnName)
Dim cell = sheet.GetCellAt(0, col)
cell.Style.Font.Bold = True
cell.Style.SetBackgroundColor("#4472C4")
cell.Style.Font.Color = "#FFFFFF"
cell.Style.BottomBorder.Type = BorderType.Thin
Next
' Data rows -- alternating row color
For row As Integer = 0 To dt.Rows.Count - 1
For col As Integer = 0 To dt.Columns.Count - 1
Dim value As String = If(dt.Rows(row)(col)?.ToString(), String.Empty)
sheet.SetCellValue(row + 1, col, value)
Dim cell = sheet.GetCellAt(row + 1, col)
cell.Style.SetBackgroundColor(If(row Mod 2 = 0, "#D6DCE5", "#FFFFFF"))
cell.Style.BottomBorder.Type = BorderType.Thin
Next
Next
' Save via dialog
Using saveDialog As New SaveFileDialog With {
.Filter = "Excel Files|*.xlsx",
.FileName = "GridViewExport.xlsx"
}
If saveDialog.ShowDialog() = DialogResult.OK Then
workBook.SaveAs(saveDialog.FileName)
MessageBox.Show("Export successful.", "Export", MessageBoxButtons.OK, MessageBoxIcon.Information)
End If
End UsingWorkBook.Create初始化一个新的内存中XLSX格式工作簿。 Name属性重命名。 DateTime值——IronXL自动选择正确的单元格类型。
交替行颜色模式——#FFFFFF——反映了Excel内置的带状行表样式。 您可以替换为任何与应用程序设计系统匹配的六位十六进制颜色代码。
输出图像



如何将 ASP.NET GridView 导出到 Excel 并将文件流式传输到浏览器?
Web 应用程序需要不同的交付机制。 您可以不写入文件系统,而是将工作簿序列化为MemoryStream并通过正确的标头将其写入HTTP响应,这样浏览器会将其视为文件下载。
对于分页GridViews的重要预处理步骤:禁用分页(AllowPaging = false)并在导出前重新绑定数据源,以确保捕获每个记录而不仅仅是当前页面。
using IronXL;
using IronXL.Styles;
using System;
using System.Data;
using System.IO;
using System.Web.UI;
// Disable paging so all rows are captured
GridView1.AllowPaging = false;
GridView1.DataBind();
DataTable dt = (DataTable)GridView1.DataSource;
WorkBook workBook = WorkBook.Create(ExcelFileFormat.XLSX);
WorkSheet sheet = workBook.DefaultWorkSheet;
// Header row
for (int col = 0; col < dt.Columns.Count; col++)
{
sheet.SetCellValue(0, col, dt.Columns[col].ColumnName);
var cell = sheet.GetCellAt(0, col);
cell.Style.Font.Bold = true;
cell.Style.SetBackgroundColor("#2E75B6");
cell.Style.Font.Color = "#FFFFFF";
cell.Style.HorizontalAlignment = HorizontalAlignment.Center;
cell.Style.BottomBorder.Type = BorderType.Medium;
}
// Data rows
for (int row = 0; row < dt.Rows.Count; row++)
{
for (int col = 0; col < dt.Columns.Count; col++)
{
sheet.SetCellValue(row + 1, col, dt.Rows[row][col]?.ToString() ?? string.Empty);
var cell = sheet.GetCellAt(row + 1, col);
cell.Style.SetBackgroundColor(row % 2 == 0 ? "#DEEAF1" : "#FFFFFF");
cell.Style.BottomBorder.Type = BorderType.Thin;
cell.Style.LeftBorder.Type = BorderType.Thin;
cell.Style.RightBorder.Type = BorderType.Thin;
}
}
// Stream to browser
byte[] fileBytes = workBook.ToByteArray();
Response.Clear();
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment; filename=GridViewExport.xlsx");
Response.BinaryWrite(fileBytes);
Response.End();Imports IronXL
Imports IronXL.Styles
Imports System
Imports System.Data
Imports System.IO
Imports System.Web.UI
' Disable paging so all rows are captured
GridView1.AllowPaging = False
GridView1.DataBind()
Dim dt As DataTable = CType(GridView1.DataSource, DataTable)
Dim workBook As WorkBook = WorkBook.Create(ExcelFileFormat.XLSX)
Dim sheet As WorkSheet = workBook.DefaultWorkSheet
' Header row
For col As Integer = 0 To dt.Columns.Count - 1
sheet.SetCellValue(0, col, dt.Columns(col).ColumnName)
Dim cell = sheet.GetCellAt(0, col)
cell.Style.Font.Bold = True
cell.Style.SetBackgroundColor("#2E75B6")
cell.Style.Font.Color = "#FFFFFF"
cell.Style.HorizontalAlignment = HorizontalAlignment.Center
cell.Style.BottomBorder.Type = BorderType.Medium
Next
' Data rows
For row As Integer = 0 To dt.Rows.Count - 1
For col As Integer = 0 To dt.Columns.Count - 1
sheet.SetCellValue(row + 1, col, If(dt.Rows(row)(col)?.ToString(), String.Empty))
Dim cell = sheet.GetCellAt(row + 1, col)
cell.Style.SetBackgroundColor(If(row Mod 2 = 0, "#DEEAF1", "#FFFFFF"))
cell.Style.BottomBorder.Type = BorderType.Thin
cell.Style.LeftBorder.Type = BorderType.Thin
cell.Style.RightBorder.Type = BorderType.Thin
Next
Next
' Stream to browser
Dim fileBytes As Byte() = workBook.ToByteArray()
Response.Clear()
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
Response.AddHeader("content-disposition", "attachment; filename=GridViewExport.xlsx")
Response.BinaryWrite(fileBytes)
Response.End()通过content-disposition: attachment在所有现代浏览器中强制弹出文件下载对话框。 MIME类型application/vnd.openxmlformats-officedocument.spreadsheetml.sheet是XLSX文件的注册类型,可防止浏览器尝试内联显示二进制内容。
对于ASP.NET Core应用程序,在控制器操作中使用Response.BinaryWrite——工作簿创建逻辑是相同的。
如何根据单元格值应用条件格式?
条件格式化功能可突出显示符合特定条件的单元格——例如,将逾期日期标记为红色,或将低于阈值的数值标记为橙色。 IronXL 在构建工作簿时会在单元格级别应用条件格式:
// Assume "DueDate" is column index 3 and "Amount" is column index 4
DateTime today = DateTime.Today;
for (int row = 0; row < dt.Rows.Count; row++)
{
// Highlight past-due dates
if (dt.Columns.Contains("DueDate") && dt.Rows[row]["DueDate"] != DBNull.Value)
{
DateTime dueDate = Convert.ToDateTime(dt.Rows[row]["DueDate"]);
var dueDateCell = sheet.GetCellAt(row + 1, 3);
if (dueDate < today)
{
dueDateCell.Style.SetBackgroundColor("#FF0000");
dueDateCell.Style.Font.Color = "#FFFFFF";
dueDateCell.Style.Font.Bold = true;
}
}
// Highlight amounts below threshold
if (dt.Columns.Contains("Amount") && dt.Rows[row]["Amount"] != DBNull.Value)
{
decimal amount = Convert.ToDecimal(dt.Rows[row]["Amount"]);
var amountCell = sheet.GetCellAt(row + 1, 4);
if (amount < 100m)
{
amountCell.Style.SetBackgroundColor("#FFC000");
}
}
}Imports System
' Assume "DueDate" is column index 3 and "Amount" is column index 4
Dim today As DateTime = DateTime.Today
For row As Integer = 0 To dt.Rows.Count - 1
' Highlight past-due dates
If dt.Columns.Contains("DueDate") AndAlso dt.Rows(row)("DueDate") IsNot DBNull.Value Then
Dim dueDate As DateTime = Convert.ToDateTime(dt.Rows(row)("DueDate"))
Dim dueDateCell = sheet.GetCellAt(row + 1, 3)
If dueDate < today Then
dueDateCell.Style.SetBackgroundColor("#FF0000")
dueDateCell.Style.Font.Color = "#FFFFFF"
dueDateCell.Style.Font.Bold = True
End If
End If
' Highlight amounts below threshold
If dt.Columns.Contains("Amount") AndAlso dt.Rows(row)("Amount") IsNot DBNull.Value Then
Dim amount As Decimal = Convert.ToDecimal(dt.Rows(row)("Amount"))
Dim amountCell = sheet.GetCellAt(row + 1, 4)
If amount < 100D Then
amountCell.Style.SetBackgroundColor("#FFC000")
End If
End If
Next row此模式支持组合使用——可根据您的报表需求添加任意数量的条件检查。 由于 IronXL 采用逐单元格处理机制,您可以在基础行样式之后应用条件样式,从而将条件格式与交替行颜色逻辑相结合。
如何设置列宽并固定标题行?
Professional 格式的 Excel 导出文件应包含适当的列宽和固定标题行,以便用户在滚动浏览大型数据集时,列名始终可见。
IronXL通过FreezeRows方法冻结标头:
// Auto-size columns 0 through the last column index
for (int col = 0; col < dt.Columns.Count; col++)
{
// Set column width in character units (1 unit ≈ one default character width)
sheet.SetColumnWidth(col, 20);
}
// Freeze the first row (index 0) so the header stays visible while scrolling
sheet.FreezeRows(1);
// Optionally set row height for the header (in points)
sheet.SetRowHeight(0, 20);' Auto-size columns 0 through the last column index
For col As Integer = 0 To dt.Columns.Count - 1
' Set column width in character units (1 unit ≈ one default character width)
sheet.SetColumnWidth(col, 20)
Next
' Freeze the first row (index 0) so the header stays visible while scrolling
sheet.FreezeRows(1)
' Optionally set row height for the header (in points)
sheet.SetRowHeight(0, 20)在实际生产环境中,建议根据每列的最大字符数来计算宽度,而非使用固定值。 迭代DataTable列值,测量字符串长度,并乘以适合选择的字体大小的字符宽度因子。
您还可以使用 C# 为 Excel 单元格设置背景色,该操作独立于行交替填充逻辑,从而实现更精细的样式控制。
如何在不使用 GridView 控件的情况下将 DataTable 导出到 Excel?
许多.NET应用程序通过服务调用或数据库查询填充数据,并将其保存在DataTable中,而不进行UI控件绑定。 您可以直接将DataTable导出到Excel,而无需实例化GridView。
对于需要在服务器端生成 Excel 文件的后台任务、定时报告和 API 端点,这是最高效的实现路径:
using IronXL;
using IronXL.Styles;
using System.Data;
public static byte[] DataTableToExcelBytes(DataTable dt, string sheetName = "Report")
{
WorkBook workBook = WorkBook.Create(ExcelFileFormat.XLSX);
WorkSheet sheet = workBook.CreateWorkSheet(sheetName);
// Header
for (int col = 0; col < dt.Columns.Count; col++)
{
sheet.SetCellValue(0, col, dt.Columns[col].ColumnName);
var cell = sheet.GetCellAt(0, col);
cell.Style.Font.Bold = true;
cell.Style.SetBackgroundColor("#4472C4");
cell.Style.Font.Color = "#FFFFFF";
}
// Data
for (int row = 0; row < dt.Rows.Count; row++)
{
for (int col = 0; col < dt.Columns.Count; col++)
{
sheet.SetCellValue(row + 1, col, dt.Rows[row][col]?.ToString() ?? string.Empty);
}
}
return workBook.ToByteArray();
}Imports IronXL
Imports IronXL.Styles
Imports System.Data
Public Shared Function DataTableToExcelBytes(dt As DataTable, Optional sheetName As String = "Report") As Byte()
Dim workBook As WorkBook = WorkBook.Create(ExcelFileFormat.XLSX)
Dim sheet As WorkSheet = workBook.CreateWorkSheet(sheetName)
' Header
For col As Integer = 0 To dt.Columns.Count - 1
sheet.SetCellValue(0, col, dt.Columns(col).ColumnName)
Dim cell = sheet.GetCellAt(0, col)
cell.Style.Font.Bold = True
cell.Style.SetBackgroundColor("#4472C4")
cell.Style.Font.Color = "#FFFFFF"
Next
' Data
For row As Integer = 0 To dt.Rows.Count - 1
For col As Integer = 0 To dt.Columns.Count - 1
sheet.SetCellValue(row + 1, col, If(dt.Rows(row)(col)?.ToString(), String.Empty))
Next
Next
Return workBook.ToByteArray()
End Function此方法会返回一个byte[],可以将其写入磁盘、从API端点流出、附加到电子邮件或缓存到内存中。 有关相关技术,请参阅将 DataTable 导出到 Excel 的指南以及关于将 DataTable 导出到 Excel 的最快方法的教程。
如何处理大型数据集并保证性能?
将数万行数据导出到 Excel 时,需注意内存分配问题。 对于大型网格中的每个单元格都创建一个新的单元格样式对象,是性能瓶颈最常见的成因。 尽可能复用样式定义,通过为范围对象设置样式而非单独设置单元格样式:
| 数据集规模 | 建议的翻译方法 | 关键考虑因素 |
|---|---|---|
| 最多 5,000 行 | 逐单元格样式循环 | 代码简洁,开销微乎其微 |
| 5,000 — 50,000 行 | 范围级样式应用 | 显著减少对象分配 |
| 50,000+ 行 | DataTable 直接导出,样式简化 | 尽量减少按单元格操作;若支持,请使用流式处理 |
对于分页的GridViews,总是设置AllowPaging = false并在导出前重新绑定。 分页功能会限制控件中可见的行数,因此分页导出仅捕获当前页面而非整个数据集——这常常是导致导出不完整错误的常见原因。
您还可以查看导出C#中的对象列表到Excel的指南,适用于强类型集合而非无类型的DataTable行。
如何在 ASP.NET Core 或 Blazor 中导出 GridView?
ASP.NET Core和Blazor应用程序没有Web Forms的DataTable,生成一个样式化工作簿,并交付一个文件。工作簿创建代码是相同的; 仅交付机制有所变化。
在 Blazor 应用程序中,通过 JavaScript 互操作触发文件下载:
// In a Blazor component or service
using IronXL;
using System.Data;
using Microsoft.JSInterop;
public async Task ExportToExcelAsync(DataTable dt, IJSRuntime js)
{
WorkBook workBook = WorkBook.Create(ExcelFileFormat.XLSX);
WorkSheet sheet = workBook.DefaultWorkSheet;
for (int col = 0; col < dt.Columns.Count; col++)
{
sheet.SetCellValue(0, col, dt.Columns[col].ColumnName);
var cell = sheet.GetCellAt(0, col);
cell.Style.Font.Bold = true;
cell.Style.SetBackgroundColor("#4472C4");
cell.Style.Font.Color = "#FFFFFF";
}
for (int row = 0; row < dt.Rows.Count; row++)
{
for (int col = 0; col < dt.Columns.Count; col++)
{
sheet.SetCellValue(row + 1, col, dt.Rows[row][col]?.ToString() ?? string.Empty);
}
}
byte[] fileBytes = workBook.ToByteArray();
string base64 = Convert.ToBase64String(fileBytes);
await js.InvokeVoidAsync("downloadFileFromBase64", base64, "GridViewExport.xlsx",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
}Imports IronXL
Imports System.Data
Imports Microsoft.JSInterop
Public Async Function ExportToExcelAsync(dt As DataTable, js As IJSRuntime) As Task
Dim workBook As WorkBook = WorkBook.Create(ExcelFileFormat.XLSX)
Dim sheet As WorkSheet = workBook.DefaultWorkSheet
For col As Integer = 0 To dt.Columns.Count - 1
sheet.SetCellValue(0, col, dt.Columns(col).ColumnName)
Dim cell = sheet.GetCellAt(0, col)
cell.Style.Font.Bold = True
cell.Style.SetBackgroundColor("#4472C4")
cell.Style.Font.Color = "#FFFFFF"
Next
For row As Integer = 0 To dt.Rows.Count - 1
For col As Integer = 0 To dt.Columns.Count - 1
sheet.SetCellValue(row + 1, col, If(dt.Rows(row)(col)?.ToString(), String.Empty))
Next
Next
Dim fileBytes As Byte() = workBook.ToByteArray()
Dim base64 As String = Convert.ToBase64String(fileBytes)
Await js.InvokeVoidAsync("downloadFileFromBase64", base64, "GridViewExport.xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
End FunctionBlazor 下载模式的完整演示详见《Blazor 导出到 Excel 教程》。 有关 ASP.NET Core 控制器实现方法,请参阅 ASP.NET Core 导出 Excel 教程。
字体样式和边框选项
IronXL通过每个单元的Style对象公开精细的字体和边框控件。 C# 中 Excel 字体的完整样式包括粗体、斜体、下划线、字号和颜色。 通过BorderType提供的边框类型包括细边框、中等边框、厚边框、虚线、点线、双线和几种细线变体。
对于合并的表头行或摘要表脚,IronXL 还支持使用 C# 在 Excel 中合并单元格——当您希望在数据表上方设置一个横跨多列的标题单元格时,此功能非常有用。
若需在填入数据后自动调整列宽,请参考《使用 C# 在 Excel 中自动调整单元格宽度》指南中的推荐方法。
为什么原生 Excel 库生成的导出结果比 HtmlTextWriter 更干净?
传统的ASP.NET导出技术——重载.xls扩展名的HTML文档。 Microsoft Excel 打开此类文件时会显示兼容性警告,因为该文件实际上并非 Excel 二进制或 OOXML 格式。 样式仅限于 Excel 能部分解析的内联 CSS。 无法使用条件格式化。 非 Windows 平台用户或使用 LibreOffice 的用户将看到质量较差的输出结果。
IronXL 可直接写入 Open XML 电子表格格式 (OOXML)。 结果是一个正确的.xlsx文件——与Excel本身创建的文件相同——在Excel、LibreOffice、Google Sheets和macOS上的Numbers中打开时没有警告。 格式采用电子表格样式编码,而非 HTML 属性,因此能够经受往返传输和跨平台查看。
| 方法 | 文件格式 | 格式提示 | 全面支持样式规范 | 办公室要求 |
|---|---|---|---|---|
| HtmlTextWriter + StringWriter | 伪装成 XLS 的 HTML | 是 | 无 | 无 |
| Office 互操作(COM) | 原生 XLS/XLSX | 无 | 是 | 是 |
| IronXL | 原生 XLSX/XLS | 无 | 是 | 无 |
微软关于 Open XML SDK 的官方文档详细说明了 IronXL 生成的底层格式。 由 ECMA International 维护的 OOXML 规范定义了确保跨应用程序兼容性的标准。 Microsoft Docs 上的 ASP.NET GridView 控件文档描述了上述导出模式所读取的控件模型。
下一步计划是什么?
现在,您已掌握使用 IronXL 将 GridView 和 DataGridView 数据导出为格式正确的 XLSX 文件所需的模式——涵盖 Windows Forms、ASP.NET Web Forms、ASP.NET Core 和 Blazor 交付模型。
更进一步:
- 立即免费试用 IronXL,使用您的数据测试其完整的格式化和导出功能。
- 请查阅 IronXL 文档以获取完整的 API 参考,包括数据透视表、图表和数据验证。
- 探索使用 C# 创建 Excel 报表,将上述导出模式与计算得出的汇总数据和图表相结合。
- 若您的应用程序还需处理上传的电子表格,请参阅《使用 C# 读取 Excel 文件》以了解相应的导入工作流。
- 关于除 XLSX 之外的 CSV 格式导出,请参阅 C# 导出为 CSV 教程。
- 若需将 DataGridView 中的数据导出,且需将列标题作为第一行,请参阅专门的《DataGridView 导出至 Excel(含列标题)指南》。

Curtis Chau 拥有卡尔顿大学的计算机科学学士学位,专注于前端开发,精通 Node.js、TypeScript、JavaScript 和 React。他热衷于打造直观且美观的用户界面,喜欢使用现代框架并创建结构良好、视觉吸引力强的手册。
相关文章



