Skip to footer content
USING IRONXL

How to Export DataGridView to Excel in C# with IronXL

Exporting data from a DataGridView to an Excel file requires just a few lines of C# code when you use IronXL. Create a WorkBook, iterate through the grid's columns and rows, write each cell value to the worksheet, then call SaveAs to produce a fully formatted .xlsx file -- no Microsoft Office installation needed.

How Do You Set Up a Windows Forms Project for Excel Export?

Windows Forms is a foundational GUI library in the .NET ecosystem, widely used for building desktop applications. The DataGridView control is one of its most-used components: it displays, edits, and manages tabular data from any bindable source such as a DataTable, a database query result, or an in-memory list.

Exporting that grid data to Excel serves several everyday needs -- sending reports to stakeholders, archiving snapshots for auditing, or feeding data into downstream analytical tools. The two traditional approaches are Microsoft Office Interop and third-party libraries. Interop requires a copy of Excel installed on every machine that runs the application, creates COM object lifecycle issues, and performs poorly in server or cloud deployments. Libraries such as IronXL, ClosedXML, and Syncfusion avoid those problems by writing directly to the Open XML file format without any Office dependency.

This guide demonstrates the IronXL approach in C# targeting .NET 10, though IronXL supports .NET Framework 4.6.2 and all modern .NET versions.

Prerequisites

Before writing any export code, confirm the following are in place:

  • Visual Studio 2022 or later
  • .NET 10 SDK installed
  • A Windows Forms App project containing a DataGridView control
  • NuGet access to install IronXL

How Do You Install IronXL?

Open the Package Manager Console in Visual Studio and run either command:

Install-Package IronXL
dotnet add package IronXL
Install-Package IronXL
dotnet add package IronXL
SHELL

Alternatively, right-click the project in Solution Explorer, choose Manage NuGet Packages, search for IronXL.Excel, and click Install.

Export Data from DataGridView to Excel in VB .NET 2010 Using IronXL: Image 1 - Installation

Once installed, add the IronXL using directive at the top of any file that uses Excel functionality:

using IronXL;
using System.Data;
using IronXL;
using System.Data;
$vbLabelText   $csharpLabel

IronXL supports every common spreadsheet format: XLSX, XLS, CSV, and TSV. This guide uses XLSX throughout because it is the default format for modern Excel versions.

How Do You Populate a DataGridView with Sample Data?

For this walkthrough, the form contains a DataGridView named DataGridView1 and a button named btnExport. The grid is populated in the form's Load event with employee records stored in a DataTable:

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

    // Define columns with the appropriate .NET type
    dt.Columns.Add("EmployeeID", typeof(int));
    dt.Columns.Add("Name", typeof(string));
    dt.Columns.Add("Department", typeof(string));
    dt.Columns.Add("Salary", typeof(decimal));

    // Add sample rows
    dt.Rows.Add(101, "Sarah Johnson", "Engineering", 85000m);
    dt.Rows.Add(102, "Michael Chen", "Marketing", 72000m);
    dt.Rows.Add(103, "Emily Davis", "Finance", 91000m);
    dt.Rows.Add(104, "James Wilson", "Engineering", 78000m);

    DataGridView1.DataSource = dt;
}
void Form1_Load(object sender, EventArgs e)
{
    var dt = new DataTable();

    // Define columns with the appropriate .NET type
    dt.Columns.Add("EmployeeID", typeof(int));
    dt.Columns.Add("Name", typeof(string));
    dt.Columns.Add("Department", typeof(string));
    dt.Columns.Add("Salary", typeof(decimal));

    // Add sample rows
    dt.Rows.Add(101, "Sarah Johnson", "Engineering", 85000m);
    dt.Rows.Add(102, "Michael Chen", "Marketing", 72000m);
    dt.Rows.Add(103, "Emily Davis", "Finance", 91000m);
    dt.Rows.Add(104, "James Wilson", "Engineering", 78000m);

    DataGridView1.DataSource = dt;
}
$vbLabelText   $csharpLabel

Each column is defined with a specific .NET type so that numeric comparisons and formatting work correctly later. The DataSource property binds the DataTable directly to the DataGridView, and the grid automatically renders all rows when the form opens. In production, this data would typically come from a database query, an ORM result set, or a REST API response rather than hard-coded values.

Export Data from DataGridView to Excel in VB .NET 2010 Using IronXL: Image 2 - DataGridView Output

Understanding the DataGridView Data Model

A DataGridView exposes its content through two collections: Columns (for metadata such as HeaderText and column index) and Rows (for the actual data cells). Each DataGridViewRow contains a Cells collection indexed by column position. The Value property of each cell returns a boxed object that you must cast or convert before writing it to an Excel cell. Understanding this hierarchy is essential for writing a reliable export loop.

The DataTable behind the scenes stores typed values, so a decimal salary does not need string conversion before being written to an IronXL worksheet. IronXL's SetCellValue method accepts string, double, decimal, int, bool, and DateTime overloads, allowing you to preserve the original data type in the output file.

How Do You Export DataGridView Data to an Excel File with Column Headers?

The export logic sits inside the button's click handler. The code creates a new WorkBook, retrieves the default worksheet, writes column headers to the first row, then writes each data row beneath them:

void btnExport_Click(object sender, EventArgs e)
{
    var workbook = WorkBook.Create();
    var sheet = workbook.DefaultWorkSheet;

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

    // Write data rows starting at row index 1
    for (int row = 0; row < DataGridView1.Rows.Count; row++)
    {
        for (int col = 0; col < DataGridView1.Columns.Count; col++)
        {
            object? cellValue = DataGridView1.Rows[row].Cells[col].Value;
            if (cellValue is not null)
            {
                sheet.SetCellValue(row + 1, col, cellValue.ToString()!);
            }
        }
    }

    string outputPath = "EmployeeData.xlsx";
    workbook.SaveAs(outputPath);
    MessageBox.Show("Export complete. File saved to: " + outputPath, "Success");
}
void btnExport_Click(object sender, EventArgs e)
{
    var workbook = WorkBook.Create();
    var sheet = workbook.DefaultWorkSheet;

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

    // Write data rows starting at row index 1
    for (int row = 0; row < DataGridView1.Rows.Count; row++)
    {
        for (int col = 0; col < DataGridView1.Columns.Count; col++)
        {
            object? cellValue = DataGridView1.Rows[row].Cells[col].Value;
            if (cellValue is not null)
            {
                sheet.SetCellValue(row + 1, col, cellValue.ToString()!);
            }
        }
    }

    string outputPath = "EmployeeData.xlsx";
    workbook.SaveAs(outputPath);
    MessageBox.Show("Export complete. File saved to: " + outputPath, "Success");
}
$vbLabelText   $csharpLabel

The WorkBook object represents the entire Excel file in memory. DefaultWorkSheet returns the first sheet without requiring you to create one explicitly. The outer loop writes header text from HeaderText into row zero. The nested loop then iterates each data row, checking for null before converting the cell value to a string. The row + 1 offset shifts data below the header row. SaveAs writes the finished workbook as an Open XML XLSX file to the specified path.

Export Data from DataGridView to Excel in VB .NET 2010 Using IronXL: Image 3 - Excel Output

The resulting file opens in Excel, Google Sheets, or any application that reads the XLSX format. Column headers appear in the first row, and all data rows follow in the same order they appeared in the DataGridView.

How Do You Apply Cell Formatting to the Exported Excel File?

A plain data dump is functional but not presentation-ready. IronXL's styling API lets you apply bold fonts, background colors, text colors, and number formats to any cell range before saving:

void ExportWithFormatting()
{
    var workbook = WorkBook.Create();
    var sheet = workbook.DefaultWorkSheet;

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

    // Style the header row: bold white text on blue background
    var headerRange = sheet.GetRange("A1:D1");
    headerRange.Style.Font.Bold = true;
    headerRange.Style.SetBackgroundColor("#4472C4");
    headerRange.Style.Font.SetColor("#FFFFFF");

    // Locate the Salary column index
    int salaryColIndex = -1;
    for (int i = 0; i < DataGridView1.Columns.Count; i++)
    {
        if (string.Equals(DataGridView1.Columns[i].HeaderText, "Salary",
            StringComparison.OrdinalIgnoreCase))
        {
            salaryColIndex = i;
            break;
        }
    }

    // Write data rows, preserving numeric types
    for (int row = 0; row < DataGridView1.Rows.Count; row++)
    {
        if (DataGridView1.Rows[row].IsNewRow) continue;

        for (int col = 0; col < DataGridView1.Columns.Count; col++)
        {
            object? cellValue = DataGridView1.Rows[row].Cells[col].Value;
            if (cellValue is null) continue;

            int targetRow = row + 1;

            if (col == salaryColIndex)
            {
                // Write salary as a true numeric decimal
                if (decimal.TryParse(cellValue.ToString(),
                    System.Globalization.NumberStyles.Number,
                    System.Globalization.CultureInfo.InvariantCulture,
                    out decimal decValue))
                {
                    sheet.SetCellValue(targetRow, col, decValue);
                }
                else
                {
                    sheet.SetCellValue(targetRow, col, cellValue.ToString()!);
                }
            }
            else
            {
                sheet.SetCellValue(targetRow, col, cellValue.ToString()!);
            }
        }
    }

    // Apply currency format to the salary column data range
    var salaryRange = sheet.GetRange("D2:D5");
    salaryRange.FormatString = "$#,##0";

    workbook.SaveAs("FormattedEmployeeData.xlsx");
}
void ExportWithFormatting()
{
    var workbook = WorkBook.Create();
    var sheet = workbook.DefaultWorkSheet;

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

    // Style the header row: bold white text on blue background
    var headerRange = sheet.GetRange("A1:D1");
    headerRange.Style.Font.Bold = true;
    headerRange.Style.SetBackgroundColor("#4472C4");
    headerRange.Style.Font.SetColor("#FFFFFF");

    // Locate the Salary column index
    int salaryColIndex = -1;
    for (int i = 0; i < DataGridView1.Columns.Count; i++)
    {
        if (string.Equals(DataGridView1.Columns[i].HeaderText, "Salary",
            StringComparison.OrdinalIgnoreCase))
        {
            salaryColIndex = i;
            break;
        }
    }

    // Write data rows, preserving numeric types
    for (int row = 0; row < DataGridView1.Rows.Count; row++)
    {
        if (DataGridView1.Rows[row].IsNewRow) continue;

        for (int col = 0; col < DataGridView1.Columns.Count; col++)
        {
            object? cellValue = DataGridView1.Rows[row].Cells[col].Value;
            if (cellValue is null) continue;

            int targetRow = row + 1;

            if (col == salaryColIndex)
            {
                // Write salary as a true numeric decimal
                if (decimal.TryParse(cellValue.ToString(),
                    System.Globalization.NumberStyles.Number,
                    System.Globalization.CultureInfo.InvariantCulture,
                    out decimal decValue))
                {
                    sheet.SetCellValue(targetRow, col, decValue);
                }
                else
                {
                    sheet.SetCellValue(targetRow, col, cellValue.ToString()!);
                }
            }
            else
            {
                sheet.SetCellValue(targetRow, col, cellValue.ToString()!);
            }
        }
    }

    // Apply currency format to the salary column data range
    var salaryRange = sheet.GetRange("D2:D5");
    salaryRange.FormatString = "$#,##0";

    workbook.SaveAs("FormattedEmployeeData.xlsx");
}
$vbLabelText   $csharpLabel

The GetRange method accepts standard Excel notation (A1:D1) to select a contiguous block of cells. Setting Style.Font.Bold, Style.SetBackgroundColor, and Style.Font.SetColor applies those formats to every cell in the selected range. For numeric columns, writing the value as a decimal rather than a string keeps the data type intact, which means Excel can apply number formatting such as $#,##0 correctly. Cells stored as strings do not respond to numeric format codes.

Export Data from DataGridView to Excel in VB .NET 2010 Using IronXL: Image 4 - Formatted Excel Output

You can extend this pattern to apply alternating row shading, column width auto-fit, or freeze panes by consulting the IronXL styling documentation.

How Do You Export DataGridView Data to CSV Instead of XLSX?

Some workflows require CSV output for compatibility with legacy systems or lightweight data pipelines. IronXL handles CSV export without any additional configuration change to the main code:

void ExportToCsv()
{
    var workbook = WorkBook.Create();
    var sheet = workbook.DefaultWorkSheet;

    for (int col = 0; col < DataGridView1.Columns.Count; col++)
    {
        sheet.SetCellValue(0, col, DataGridView1.Columns[col].HeaderText);
    }

    for (int row = 0; row < DataGridView1.Rows.Count; row++)
    {
        if (DataGridView1.Rows[row].IsNewRow) continue;

        for (int col = 0; col < DataGridView1.Columns.Count; col++)
        {
            object? cell = DataGridView1.Rows[row].Cells[col].Value;
            if (cell is not null)
                sheet.SetCellValue(row + 1, col, cell.ToString()!);
        }
    }

    // Saving with a .csv extension produces a comma-separated file
    workbook.SaveAs("EmployeeData.csv");
}
void ExportToCsv()
{
    var workbook = WorkBook.Create();
    var sheet = workbook.DefaultWorkSheet;

    for (int col = 0; col < DataGridView1.Columns.Count; col++)
    {
        sheet.SetCellValue(0, col, DataGridView1.Columns[col].HeaderText);
    }

    for (int row = 0; row < DataGridView1.Rows.Count; row++)
    {
        if (DataGridView1.Rows[row].IsNewRow) continue;

        for (int col = 0; col < DataGridView1.Columns.Count; col++)
        {
            object? cell = DataGridView1.Rows[row].Cells[col].Value;
            if (cell is not null)
                sheet.SetCellValue(row + 1, col, cell.ToString()!);
        }
    }

    // Saving with a .csv extension produces a comma-separated file
    workbook.SaveAs("EmployeeData.csv");
}
$vbLabelText   $csharpLabel

The only change from the XLSX export is the file extension passed to SaveAs. IronXL detects the extension and serializes the workbook in the correct format automatically. This consistency means your data-writing logic stays identical regardless of output format -- a significant advantage over libraries that require separate code paths for each format.

CSV export is especially useful when the downstream consumer is a Python pandas script, a database bulk-import tool, or an analytics platform that cannot read binary XLSX files.

How Do You Handle Large DataGridView Datasets Efficiently?

For grids containing tens of thousands of rows, performance becomes a consideration. The following pattern reduces memory pressure by constructing the full dataset in a single pass:

IronXL export method comparison for large datasets
Approach Rows handled Office required Type preservation
Microsoft.Office.Interop.Excel Up to ~65k (slow) Yes Partial
IronXL (string cells) 1M+ rows No No (all text)
IronXL (typed cells) 1M+ rows No Yes
IronXL from DataTable 1M+ rows No Yes (auto)

When the DataGridView is bound to a DataTable, you can load the table directly into IronXL using the WorkSheet.LoadDataTable method, bypassing the cell-by-cell iteration entirely. This approach is faster and preserves all column types automatically.

For grids not backed by a DataTable, the cell-by-cell pattern shown earlier remains the standard approach. If you need to export asynchronously to keep the UI responsive during large exports, wrap the export logic in a Task.Run call and await the result on a background thread. See the async file operations documentation for patterns on marshaling results back to the UI thread.

Why Is IronXL Better Than Office Interop for DataGridView Export?

Traditional .NET solutions used Microsoft.Office.Interop.Excel to drive a running Excel process. That approach creates several deployment and reliability problems:

  • Every machine running the application needs a licensed copy of Microsoft Excel installed
  • Server environments and cloud containers typically cannot install Office
  • COM Interop requires explicit release of every object to avoid memory leaks and zombie Excel processes
  • Error handling across the COM boundary is verbose and brittle
  • Performance degrades quickly as row counts grow

IronXL writes directly to the OOXML file format without launching any external process. Applications deploy as self-contained units. The library's API is fully managed .NET, so garbage collection handles memory automatically without Marshal.ReleaseComObject calls. Speed is substantially higher because no inter-process communication occurs.

For teams evaluating alternatives, ClosedXML is a popular open-source option. IronXL offers a broader feature set including PDF conversion, chart generation, and commercial support, which may be factors in enterprise procurement decisions. Review the IronXL licensing options to match the right tier to your team size and deployment scenario.

Feature comparison: IronXL vs Office Interop
Feature IronXL Office Interop
Office installation required No Yes
Server / cloud deployment Yes No (unsupported)
Managed memory model Yes No (COM cleanup required)
XLSX / CSV / XLS formats All three Depends on installed Excel
PDF export from spreadsheet Yes Requires additional library

The IronXL tutorials section covers reading existing Excel files, modifying templates, generating charts, and applying conditional formatting -- all capabilities that extend naturally from the DataGridView export pattern shown here.

What Are Your Next Steps?

You now have working C# code to export a DataGridView to a formatted Excel file using IronXL. From here, consider the following directions:

  • Add error handling: Wrap the export code in a try/catch block and display a user-friendly message if the file is locked or the path is invalid
  • Support file path selection: Use SaveFileDialog to let users choose the output location and filename at runtime
  • Load real data: Replace the sample DataTable with a database query using ADO.NET or Entity Framework
  • Read existing files: Use WorkBook.Load to open an existing spreadsheet and update it rather than always creating a new one
  • Export to multiple sheets: Create additional WorkSheet objects in the same WorkBook to organize related datasets
  • Apply conditional formatting: Highlight cells that exceed thresholds using IronXL's conditional formatting API
  • Review the licensing options: A free trial is available; licensing tiers cover individual developers through enterprise deployments
  • Browse the full API reference: The IronXL object reference documents every class and method available

Frequently Asked Questions

What is the easiest way to export DataGridView data to Excel in C#?

Using IronXL, you can export DataGridView data to Excel in C# with a short loop that writes column headers and data rows to a WorkBook object, then calls SaveAs to produce an XLSX file. No Microsoft Office installation is required.

How do you use IronXL to handle Excel files in a C# Windows Forms application?

Install IronXL via NuGet, add a using IronXL directive, create a WorkBook with WorkBook.Create(), write data using SetCellValue, and save with SaveAs. IronXL supports XLSX, XLS, and CSV formats.

Does IronXL support exporting large DataGridView datasets to Excel?

Yes, IronXL handles large datasets efficiently. For DataGridViews backed by a DataTable, you can use the LoadDataTable method to bypass cell-by-cell iteration for even better performance.

Do you need Microsoft Excel installed to use IronXL?

No. IronXL writes directly to the Open XML file format without launching Excel or any COM automation. Applications built with IronXL deploy to servers and cloud environments where Office is not available.

What are the benefits of using IronXL for Excel exports over Office Interop?

IronXL does not require Office installation, avoids COM memory leak issues, supports server and cloud deployment, and provides a clean managed .NET API for reading and writing XLSX, XLS, and CSV files.

Can IronXL export DataGridView data to CSV as well as XLSX?

Yes. Passing a .csv file path to WorkBook.SaveAs produces a comma-separated file. The data-writing code is identical for both formats -- only the file extension changes.

How do you apply formatting to exported Excel cells with IronXL?

Use WorkSheet.GetRange to select a cell range, then access the Style property to set Font.Bold, SetBackgroundColor, Font.SetColor, and FormatString for number formats.

How do you start using IronXL in a C# project?

Run Install-Package IronXL or dotnet add package IronXL in your project, add using IronXL at the top of your file, and follow the examples in the IronXL documentation at ironsoftware.com/csharp/excel/.

Jordi Bardia
Software Engineer
Jordi is most proficient in Python, C# and C++, when he isn’t leveraging his skills at Iron Software; he’s game programming. Sharing responsibilities for product testing, product development and research, Jordi adds immense value to continual product improvement. The varied experience keeps him challenged and engaged, and he ...
Read More

Iron Support Team

We're online 24 hours, 5 days a week.
Chat
Email
Call Me