跳至页脚内容
USING IRONXL

C# 将 DataGridView 导出到 Excel 并带列标题

如何在C#中将DataGridView导出为带列标题的Excel?

将 Windows Forms DataGridView 控件中的数据导出为 Excel 格式是一个常见的需求,但开发人员经常会遇到一个令人沮丧的问题:导出的文件缺少列标题。 当您需要将 DataGridView 导出到 Excel 并保留列标题时,解决方案必须能够可靠地保留所有数据和格式。 使用 Microsoft Office Interop 的传统方法可能速度慢、不稳定,并且需要在运行代码的每台计算机上安装 MS Excel。

IronXL可以完美地解决这个问题。 这是一个.NET Excel 库,可以读取、创建和写入 Excel 文件,而无需任何 Office 依赖项。 本教程将引导您完成一个完整的导出解决方案——只需几行代码即可处理列标题、数据类型、空单元格和用户友好的文件保存。

最后,您将拥有一个可用的 Windows Forms 按钮处理程序,该处理程序可以将 DataGridView 导出到 XLSX 文件,并保留所有列标题。

开始之前你需要准备什么

在编写任何代码之前,请确保以下事项已就绪:

  • Visual Studio 2022 或更高版本(任何版本) 已安装.NET 10 SDK
  • 一个面向.NET 10 的 Windows 窗体应用程序项目 -NuGet访问来安装IronXL

下面的例子使用顶级语句和现代 .NET 10 项目结构。

如何在.NET项目中安装库?

在 Visual Studio 中打开NuGet程序包管理器控制台,并运行以下任一命令。 该软件包已在NuGet Gallery上列出,面向.NET Standard 2.0 及更高版本,因此可与任何现代.NET项目配合使用。

Install-Package IronXL.Excel
dotnet add package IronXL.Excel

安装完成后,请在表单文件顶部添加所需的命名空间:

using IronXL;
using System;
using System.Data;
using System.Windows.Forms;
using IronXL;
using System;
using System.Data;
using System.Windows.Forms;
Imports IronXL
Imports System
Imports System.Data
Imports System.Windows.Forms
$vbLabelText   $csharpLabel

这些导入功能可以访问IronXL 的 Excel 功能、数据表操作以及导出过程所需的 Windows 窗体控件。

如何使用示例数据设置 DataGridView?

首先在 Visual Studio 中创建一个 Windows 窗体应用程序。 通过设计器向主窗体添加一个名为btnExport的按钮。 然后在表单加载时填充表格:

using System;
using System.Data;
using System.Windows.Forms;

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        DataTable dt = new DataTable();

        // Define columns -- these names become Excel headers
        dt.Columns.Add("Product ID", typeof(int));
        dt.Columns.Add("Product Name", typeof(string));
        dt.Columns.Add("Price", typeof(decimal));
        dt.Columns.Add("Stock Quantity", typeof(int));

        // Add sample rows
        dt.Rows.Add(1001, "Laptop", 999.99m, 15);
        dt.Rows.Add(1002, "Mouse", 29.99m, 50);
        dt.Rows.Add(1003, "Keyboard", 79.99m, 30);
        dt.Rows.Add(1004, "Monitor", 299.99m, 12);
        dt.Rows.Add(1005, "Headphones", 89.99m, 25);

        // Bind data to the grid
        dataGridView1.DataSource = dt;
    }
}
using System;
using System.Data;
using System.Windows.Forms;

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        DataTable dt = new DataTable();

        // Define columns -- these names become Excel headers
        dt.Columns.Add("Product ID", typeof(int));
        dt.Columns.Add("Product Name", typeof(string));
        dt.Columns.Add("Price", typeof(decimal));
        dt.Columns.Add("Stock Quantity", typeof(int));

        // Add sample rows
        dt.Rows.Add(1001, "Laptop", 999.99m, 15);
        dt.Rows.Add(1002, "Mouse", 29.99m, 50);
        dt.Rows.Add(1003, "Keyboard", 79.99m, 30);
        dt.Rows.Add(1004, "Monitor", 299.99m, 12);
        dt.Rows.Add(1005, "Headphones", 89.99m, 25);

        // Bind data to the grid
        dataGridView1.DataSource = dt;
    }
}
Imports System
Imports System.Data
Imports System.Windows.Forms

Public Partial Class Form1
    Inherits Form

    Public Sub New()
        InitializeComponent()
    End Sub

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim dt As New DataTable()

        ' Define columns -- these names become Excel headers
        dt.Columns.Add("Product ID", GetType(Integer))
        dt.Columns.Add("Product Name", GetType(String))
        dt.Columns.Add("Price", GetType(Decimal))
        dt.Columns.Add("Stock Quantity", GetType(Integer))

        ' Add sample rows
        dt.Rows.Add(1001, "Laptop", 999.99D, 15)
        dt.Rows.Add(1002, "Mouse", 29.99D, 50)
        dt.Rows.Add(1003, "Keyboard", 79.99D, 30)
        dt.Rows.Add(1004, "Monitor", 299.99D, 12)
        dt.Rows.Add(1005, "Headphones", 89.99D, 25)

        ' Bind data to the grid
        dataGridView1.DataSource = dt
    End Sub
End Class
$vbLabelText   $csharpLabel

dt.Columns.Add(...)调用中定义的列名将成为导出Excel文件中的标题行。您可以在此处替换任何数据源——数据库查询结果、CSV导入或存储为DataTable的API响应都可以与稍后显示的导出代码相同地工作。 DataTable方法特别方便,因为DataGridView公开了一个IBindingList,这意味着相同的导出代码可以在每种绑定场景中通用而无需修改。

如果您的DataGridView是使用SqlDataAdapter从数据库填充的,则DataTable已包含类型化的列。 将这些类型化的值传递给ToString(),可以在Excel输出中保持数值列的数值,这对于任何下游报告或数据透视表使用都很重要。

这将创建一个包含所有数据的 DataGridView:

C#使用IronXL将DataGridView导出到Excel并带有列标题:图像1 - DataGridView中的示例数据

对于更高级的数据绑定场景,微软关于DataGridView 数据绑定的文档提供了更多示例。

如何在将 DataGridView 导出到 Excel 时保留列标题?

导出方法从每个DataGridView列的HeaderText属性读取列标题,并将它们写入工作表的第0行。 数据行从第 1 行开始。 将此方法绑定到btnExport单击事件:

private void btnExport_Click(object sender, EventArgs e)
{
    try
    {
        // Create a new Excel workbook in XLSX format
        WorkBook workbook = WorkBook.Create(ExcelFileFormat.XLSX);
        WorkSheet worksheet = workbook.CreateWorkSheet("Exported Data");

        // Write column headers to row 0
        for (int col = 0; col < dataGridView1.Columns.Count; col++)
        {
            worksheet.SetCellValue(0, col, dataGridView1.Columns[col].HeaderText);
        }

        // Write data rows starting at row 1
        for (int row = 0; row < dataGridView1.Rows.Count; row++)
        {
            // Skip the placeholder new-row at the bottom of the grid
            if (dataGridView1.AllowUserToAddRows && row == dataGridView1.Rows.Count - 1)
                continue;

            for (int col = 0; col < dataGridView1.Columns.Count; col++)
            {
                var cellValue = dataGridView1.Rows[row].Cells[col].Value;
                if (cellValue != null)
                {
                    worksheet.SetCellValue(row + 1, col, cellValue.ToString());
                }
            }
        }

        // Prompt the user to choose a save location
        using SaveFileDialog saveFileDialog = new SaveFileDialog
        {
            Filter = "Excel Files|*.xlsx",
            FileName = "DataGridView_Export.xlsx"
        };

        if (saveFileDialog.ShowDialog() == DialogResult.OK)
        {
            workbook.SaveAs(saveFileDialog.FileName);
            MessageBox.Show("Export completed successfully!", "Success",
                            MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show($"Export failed: {ex.Message}", "Error",
                       MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}
private void btnExport_Click(object sender, EventArgs e)
{
    try
    {
        // Create a new Excel workbook in XLSX format
        WorkBook workbook = WorkBook.Create(ExcelFileFormat.XLSX);
        WorkSheet worksheet = workbook.CreateWorkSheet("Exported Data");

        // Write column headers to row 0
        for (int col = 0; col < dataGridView1.Columns.Count; col++)
        {
            worksheet.SetCellValue(0, col, dataGridView1.Columns[col].HeaderText);
        }

        // Write data rows starting at row 1
        for (int row = 0; row < dataGridView1.Rows.Count; row++)
        {
            // Skip the placeholder new-row at the bottom of the grid
            if (dataGridView1.AllowUserToAddRows && row == dataGridView1.Rows.Count - 1)
                continue;

            for (int col = 0; col < dataGridView1.Columns.Count; col++)
            {
                var cellValue = dataGridView1.Rows[row].Cells[col].Value;
                if (cellValue != null)
                {
                    worksheet.SetCellValue(row + 1, col, cellValue.ToString());
                }
            }
        }

        // Prompt the user to choose a save location
        using SaveFileDialog saveFileDialog = new SaveFileDialog
        {
            Filter = "Excel Files|*.xlsx",
            FileName = "DataGridView_Export.xlsx"
        };

        if (saveFileDialog.ShowDialog() == DialogResult.OK)
        {
            workbook.SaveAs(saveFileDialog.FileName);
            MessageBox.Show("Export completed successfully!", "Success",
                            MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show($"Export failed: {ex.Message}", "Error",
                       MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}
Private Sub btnExport_Click(sender As Object, e As EventArgs)
    Try
        ' Create a new Excel workbook in XLSX format
        Dim workbook As WorkBook = WorkBook.Create(ExcelFileFormat.XLSX)
        Dim worksheet As WorkSheet = workbook.CreateWorkSheet("Exported Data")

        ' Write column headers to row 0
        For col As Integer = 0 To dataGridView1.Columns.Count - 1
            worksheet.SetCellValue(0, col, dataGridView1.Columns(col).HeaderText)
        Next

        ' Write data rows starting at row 1
        For row As Integer = 0 To dataGridView1.Rows.Count - 1
            ' Skip the placeholder new-row at the bottom of the grid
            If dataGridView1.AllowUserToAddRows AndAlso row = dataGridView1.Rows.Count - 1 Then
                Continue For
            End If

            For col As Integer = 0 To dataGridView1.Columns.Count - 1
                Dim cellValue = dataGridView1.Rows(row).Cells(col).Value
                If cellValue IsNot Nothing Then
                    worksheet.SetCellValue(row + 1, col, cellValue.ToString())
                End If
            Next
        Next

        ' Prompt the user to choose a save location
        Using saveFileDialog As New SaveFileDialog With {
            .Filter = "Excel Files|*.xlsx",
            .FileName = "DataGridView_Export.xlsx"
        }
            If saveFileDialog.ShowDialog() = DialogResult.OK Then
                workbook.SaveAs(saveFileDialog.FileName)
                MessageBox.Show("Export completed successfully!", "Success",
                                MessageBoxButtons.OK, MessageBoxIcon.Information)
            End If
        End Using
    Catch ex As Exception
        MessageBox.Show($"Export failed: {ex.Message}", "Error",
                       MessageBoxButtons.OK, MessageBoxIcon.Error)
    End Try
End Sub
$vbLabelText   $csharpLabel

分解导出步骤

该方法的每个步骤都有其特定目的:

  • WorkBook.Create :使用 XLSX 格式在内存中初始化一个新的 Excel 文件。 在调用SaveAs之前,没有文件会写入磁盘。
  • CreateWorkSheet :添加一个命名的工作表来保存导出的数据。 在 Excel 中,"导出数据"会显示为标签页名称。
  • 列标题循环:读取每列的dataGridView1.Columns[col].HeaderText并将其写入行索引0。这是保留标题的关键步骤。
  • 数据行循环:嵌套循环遍历每一行和列,使用row + 1作为Excel行索引,因此数据始终从标题行以下开始。 -空值检查:防止单元格不包含值时出现异常,这在实际数据中很常见。
  • SaveFileDialog :允许用户在运行时选择文件名和目标位置,而不是硬编码路径。

导出的文件如下所示:

C#使用IronXL将DataGridView导出到Excel并带有列标题:图像2 - 导出示例数据的输出Excel文件

导出过程中如何处理常见极端情况?

现实世界的数据很少像样本数据集那样干净。 以下是您最有可能遇到的情况以及应对方法。

空单元格

数据循环中的空检查(if (cellValue != null))可以处理空单元格而不会抛出异常。 在 Excel 输出中,空白单元格将保持空白,从而保留网格结构。

混合数据类型

IronXL可以自动处理不同的数据格式。 当您通过ToString()将数字作为字符串传递时,Excel可能仍会根据值将其识别为数值。 为了精确控制数据类型,请在写入之前将单元格值强制转换为正确的类型:

if (cellValue is int intVal)
    worksheet.SetCellValue(row + 1, col, intVal);
else if (cellValue is decimal decVal)
    worksheet.SetCellValue(row + 1, col, (double)decVal);
else
    worksheet.SetCellValue(row + 1, col, cellValue?.ToString() ?? string.Empty);
if (cellValue is int intVal)
    worksheet.SetCellValue(row + 1, col, intVal);
else if (cellValue is decimal decVal)
    worksheet.SetCellValue(row + 1, col, (double)decVal);
else
    worksheet.SetCellValue(row + 1, col, cellValue?.ToString() ?? string.Empty);
If TypeOf cellValue Is Integer Then
    Dim intVal As Integer = CType(cellValue, Integer)
    worksheet.SetCellValue(row + 1, col, intVal)
ElseIf TypeOf cellValue Is Decimal Then
    Dim decVal As Decimal = CType(cellValue, Decimal)
    worksheet.SetCellValue(row + 1, col, CDbl(decVal))
Else
    worksheet.SetCellValue(row + 1, col, If(cellValue?.ToString(), String.Empty))
End If
$vbLabelText   $csharpLabel

这种方法可以保持 Excel 中的数值列为数值型,以便后续的公式和排序功能能够正常工作。

标题中的特殊字符

具有特殊字符的列标题,例如&, <, >,以及重音字母可以正确导出。 IronXL会自动处理编码,无需您进行任何转义操作。

大型数据集

对于包含数万行的网格,可考虑将导出逻辑移动到后台线程以保持UI的响应。将Task.Run调用中,并从完成的回调中更新UI。 微软关于 使用 Task 进行异步编程的文档详细解释了这种模式。

对于单元格样式公式保留和密码保护等其他场景, IronXL文档对每一种场景都有详细介绍。

主要出口方式有何异同?

在决定使用某个库之前,了解最常用方法之间的优缺点会很有帮助。

C# 中 DataGridView 与 Excel 导出方法的比较
方法 办公室要求 列标题 表现 服务器安全
Microsoft Office Interop 手册 慢的
OpenXml SDK 手册 快速地
ClosedXML 手册 好的
IronXL 自动翻译 快速地

基于互操作性的解决方案需要在服务器上安装 Excel,这既是许可问题,也是部署复杂性问题。 OpenXml SDK 功能强大但底层——编写标题行需要手动构建 XML 结构。 IronXL和ClosedXML都提供高级别API,但IronXL的工作簿和工作表模型与开发人员已经对电子表格的思维方式更加一致。

如何导出为 CSV 而不是 XLSX?

如果您需要 CSV文件而不是Excel工作簿,则可以应用相同的导出模式。 更改文件格式和扩展名:

WorkBook csvWorkbook = WorkBook.Create(ExcelFileFormat.CSV);
WorkSheet csvSheet = csvWorkbook.CreateWorkSheet("Data");

// Headers and data loops remain identical

using SaveFileDialog dialog = new SaveFileDialog
{
    Filter = "CSV Files|*.csv",
    FileName = "DataGridView_Export.csv"
};

if (dialog.ShowDialog() == DialogResult.OK)
    csvWorkbook.SaveAs(dialog.FileName);
WorkBook csvWorkbook = WorkBook.Create(ExcelFileFormat.CSV);
WorkSheet csvSheet = csvWorkbook.CreateWorkSheet("Data");

// Headers and data loops remain identical

using SaveFileDialog dialog = new SaveFileDialog
{
    Filter = "CSV Files|*.csv",
    FileName = "DataGridView_Export.csv"
};

if (dialog.ShowDialog() == DialogResult.OK)
    csvWorkbook.SaveAs(dialog.FileName);
Imports System.Windows.Forms

Dim csvWorkbook As WorkBook = WorkBook.Create(ExcelFileFormat.CSV)
Dim csvSheet As WorkSheet = csvWorkbook.CreateWorkSheet("Data")

' Headers and data loops remain identical

Using dialog As New SaveFileDialog With {
    .Filter = "CSV Files|*.csv",
    .FileName = "DataGridView_Export.csv"
}
    If dialog.ShowDialog() = DialogResult.OK Then
        csvWorkbook.SaveAs(dialog.FileName)
    End If
End Using
$vbLabelText   $csharpLabel

当使用系统不支持 XLSX 格式,或者对于非常大的数据集来说文件大小是一个问题时,CSV 导出非常有用。

如何在导出的文件中设置标题行的样式?

导出的数据如果标题行在视觉上清晰可见,则更易于阅读。 IronXL提供单元格样式选项,让您在写入标题值后应用粗体文本、背景色和字体大小:

// Write headers and apply bold styling
for (int col = 0; col < dataGridView1.Columns.Count; col++)
{
    string cellAddress = worksheet.GetCellAddress(0, col);
    worksheet[cellAddress].Value = dataGridView1.Columns[col].HeaderText;
    worksheet[cellAddress].Style.Font.Bold = true;
    worksheet[cellAddress].Style.SetBackgroundColor("#4472C4");
    worksheet[cellAddress].Style.Font.FontColor = "#FFFFFF";
}
// Write headers and apply bold styling
for (int col = 0; col < dataGridView1.Columns.Count; col++)
{
    string cellAddress = worksheet.GetCellAddress(0, col);
    worksheet[cellAddress].Value = dataGridView1.Columns[col].HeaderText;
    worksheet[cellAddress].Style.Font.Bold = true;
    worksheet[cellAddress].Style.SetBackgroundColor("#4472C4");
    worksheet[cellAddress].Style.Font.FontColor = "#FFFFFF";
}
' Write headers and apply bold styling
For col As Integer = 0 To dataGridView1.Columns.Count - 1
    Dim cellAddress As String = worksheet.GetCellAddress(0, col)
    worksheet(cellAddress).Value = dataGridView1.Columns(col).HeaderText
    worksheet(cellAddress).Style.Font.Bold = True
    worksheet(cellAddress).Style.SetBackgroundColor("#4472C4")
    worksheet(cellAddress).Style.Font.FontColor = "#FFFFFF"
Next col
$vbLabelText   $csharpLabel

带有样式的标题行使导出的文件可以直接用于报告,而无需收件人手动应用格式。 有关样式属性的完整列表,请参阅IronXL单元格样式参考

如何开始免费试用?

IronXL提供免费试用版,让您可以测试所有功能,包括本文中所示的导出工作流程。 使用上面显示的任一NuGet命令安装该软件包,在IronXL许可页面上生成试用密钥,并在首次调用库之前将其设置到您的应用程序中:

IronXL.License.LicenseKey = "YOUR-LICENSE-KEY-HERE";
IronXL.License.LicenseKey = "YOUR-LICENSE-KEY-HERE";
Imports IronXL

IronXL.License.LicenseKey = "YOUR-LICENSE-KEY-HERE"
$vbLabelText   $csharpLabel

该试用版会生成功能齐全的 Excel 文件,并且不会限制哪些功能可用。 对于生产部署,许可选项涵盖单个开发人员、团队和免版税再分发。

对于相关的导出场景,探索IronXL如何处理将DataTables直接导出为Excel将Excel文件读取到DataGridViews中,以及从导出数据中创建图表

为您的用例选择合适的出口策略

本教程中展示的逐单元格导出方法简单直接,适用于大多数 Windows Forms 应用程序。 如果您的DataGridView绑定到一个DataTable,您也可以将DataTable直接传递给IronXL的DataTable到工作表转换器,它会自动处理标题行。 如果列布局固定,并且您希望代码路径最短,请选择直接使用 DataTable 的方法。 当您需要对每个单元格应用条件逻辑时,请选择逐单元格手动操作的方法——例如,突出显示值超出可接受范围的单元格,或者在写入之前显式映射可空类型。

对于生成可下载 Excel 报表的服务器端场景(例如ASP.NET Core控制器),同样的IronXL API 也适用。 唯一的区别是保存目标:调用application/vnd.openxmlformats-officedocument.spreadsheetml.sheet内容类型将字节写入HTTP响应。 无论输出到文件还是流,列标题的传输方式都完全相同。

常见问题解答

如何在 C# 中将 DataGridView 数据导出到 Excel?

使用IronXL库创建一个 Excel 工作簿,遍历 DataGridView 列,将标题写入第 0 行,然后遍历数据行,从第 1 行开始写入单元格值。使用 SaveAs 保存工作簿。

using IronXL 导出数据有什么好处?

IronXL提供了一个用于 Excel 操作的高级 API,无需安装 Microsoft Office。它能够处理标题、数据类型和文件格式,无需手动操作 XML。

从 DataGridView 导出到 Excel 时能否保留列标题?

是的。在写入任何数据行之前,请读取每个 DataGridView 列的 HeaderText 属性,并将其写入IronXL工作表的第 0 行。

开始使用 IronXL 导出到 Excel 是否需要试用版?

我们提供免费试用版,试用版可访问所有功能。请安装NuGet包,生成试用密钥,并在调用任何库之前设置IronXL。

IronXL.Excel 能否在导出到 Excel 时处理大型 DataGridView 数据集?

是的。对于非常大的网格,可以使用 Task.Run 在后台线程中运行导出操作,以在IronXL写入数据时保持 UI 的响应性。

using IronXL.Excel 将 DataGridView 导出到 Excel 的步骤是什么?

安装IronXL,创建一个 WorkBook 和 WorkSheet,遍历 DataGridView 列以在第 0 行写入标题,遍历行以从第 1 行开始写入数据,然后调用 SaveAs 保存文件。

为什么选择 IronXL 而不是其他导出到 Excel 的库?

IronXL无需安装 Office,可在服务器上运行,并提供简洁的工作簿/工作表 API,自然地与开发人员对电子表格的思考方式相匹配——并具有强大的文档和积极的支持。

IronXL 是否提供故障排除支持?

是的。IronXL 为授权客户提供详细的 API 文档、代码示例和直接的工程支持。

IronXL.Excel 能否自定义 Excel 导出过程?

是的。写入数据后,您可以使用 IronXL 的样式 API 对任何单元格区域应用粗体字体、背景颜色、边框和数字格式。

IronXL 是否支持将数据导出为 Excel 以外的其他格式?

是的。IronXL 支持 XLSX、XLS、CSV 和 TSV 格式。IronXL格式只需更改传递给 WorkBook.Create 的 ExcelFileFormat 枚举值即可。

Curtis Chau
技术作家

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

除了开发之外,Curtis 对物联网 (IoT) 有浓厚的兴趣,探索将硬件和软件集成的新方法。在空闲时间,他喜欢玩游戏和构建 Discord 机器人,将他对技术的热爱与创造力相结合。

钢铁支援团队

我们每周 5 天,每天 24 小时在线。
聊天
电子邮件
打电话给我