How to Export DataGrid to Excel in C

Cody Schneider8 min read

Exporting data from a desktop application into an Excel spreadsheet is standard practice for developers. It bridges the gap between your custom software and the world's most popular tool for data analysis and reporting. This tutorial will walk you through the most effective methods for exporting data from a WPF or WinForms DataGrid to an Excel file using C#, focusing on modern, efficient techniques.

GraphedGraphed

Build AI Agents for Marketing

Build virtual employees that run your go to market. Connect your data sources, deploy autonomous agents, and grow your company.

Watch Graphed demo video

Why Bother Exporting to Excel?

While UIs are great for interaction, Excel provides a universally understood format for analysis, sharing, and reporting. Users often want data in Excel for a few key reasons:

  • Familiarity and Flexibility: Nearly everyone in a business setting knows their way around Excel. They can sort, filter, and create pivot tables without needing any new training.
  • Offline Analysis: An exported Excel file allows users to manipulate and review data without being connected to your application or database.
  • Simple Reporting: It's the quickest way to share a snapshot of data with managers or colleagues who don't have access to your application.
  • Advanced Functionality: Users can leverage Excel's powerful features, like creating complex charts, running formulas, and using Power Query for further data transformation.

Giving users an "Export to Excel" button is often a small feature with a huge impact on your application's usability.

The Recommended Method: Using a Third-Party Library

While Microsoft provides its own library for working with Office applications (known as Office Interop), we strongly recommend using a modern, third-party library for several critical reasons:

  • No Excel Installation Required: Libraries like ClosedXML or EPPlus create .xlsx files directly. This means your application works even if the user (or your server) doesn't have Microsoft Office installed.
  • Better Performance: Interop is notoriously slow and resource-heavy because it automates the full Excel application in the background. Lightweight libraries are significantly faster.
  • Increased Stability: Improperly managed Interop calls can leave "zombie" Excel processes running in the background, consuming memory. Third-party libraries avoid this complexity entirely.

For this guide, we'll use ClosedXML, a free and powerful open-source library that's very intuitive to work with.

Setting Up Your Project with ClosedXML

Before writing any code, you need to add the ClosedXML library to your project using the NuGet Package Manager in Visual Studio.

  1. Right-click on your project in the Solution Explorer and select "Manage NuGet Packages..."
  2. In the "Browse" tab, search for ClosedXML.
  3. Select the package from the list and click "Install". Visual Studio will handle downloading and referencing everything you need.

That's it! You're now ready to start exporting data.

Step-by-Step Guide: Exporting DataGrid to Excel with ClosedXML

Let's imagine you have a simple WPF application with a DataGrid displaying a list of customers. The goal is to export this grid's content to a new Excel file when a user clicks a button.

Step 1: Get Your Data Ready

First, assume you have a DataGrid populated with data. For ClosedXML to work most effectively, it helps to first convert your DataGrid's contents into a System.Data.DataTable. This provides a structured, tabular format that the library understands perfectly.

Here is a helper method you can add to your code-behind file. It iterates through the items in your DataGrid and programmatically builds a DataTable that mirrors its structure and content.

using System.Data,
using System.ComponentModel,

public DataTable ToDataTable<T>(IList<T> data)
{
    PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T)),
    DataTable table = new DataTable(),
    foreach (PropertyDescriptor prop in properties)
    {
        table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType),
    }
    foreach (T item in data)
    {
        DataRow row = table.NewRow(),
        foreach (PropertyDescriptor prop in properties)
        {
            row[prop.Name] = prop.GetValue(item) ?? DBNull.Value,
        }
        table.Rows.Add(row),
    }
    return table,
}

Note: This generic helper converts any IList<T> of objects into a DataTable. It uses reflection to get property names for the columns.

Free PDF · the crash course

AI Agents for Marketing Crash Course

Learn how to deploy AI marketing agents across your go-to-market — the best tools, prompts, and workflows to turn your data into autonomous execution without writing code.

Step 2: Create the Export Function

Now, let’s create the event handler for our "Export" button. This function will orchestrate the entire process.

using ClosedXML.Excel,
using Microsoft.Win32,
// ... other usings

private void ExportToExcelButton_Click(object sender, RoutedEventArgs e)
{
    // Make sure your DataGrid.ItemsSource is not null and is populated
    var data = yourDataGrid.ItemsSource as IList<Customer>,
    if (data == null || data.Count == 0)
    {
        MessageBox.Show("No data to export.", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning),
        return,
    }

    // Convert the data to a DataTable
    DataTable dataTable = ToDataTable(data),

    try
    {
        // Prompt user to select a save location
        SaveFileDialog saveFileDialog = new SaveFileDialog
        {
            Filter = "Excel Workbook|*.xlsx",
            Title = "Save an Excel File"
        },

        if (saveFileDialog.ShowDialog() == true)
        {
            using (var workbook = new XLWorkbook())
            {
                // Add the DataTable as a worksheet
                var worksheet = workbook.Worksheets.Add(dataTable, "Customers Report"),

                // Optional: Add styling here (see next section)

                // Save the workbook to the selected file path
                workbook.SaveAs(saveFileDialog.FileName),
                MessageBox.Show("Export successful!", "Success", MessageBoxButton.OK, MessageBoxImage.Information),
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show($"An error occurred during export: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error),
    }
}

This code does the following:

  1. Checks if there's data to export.
  2. Converts your DataGrid's items to a DataTable using our helper method.
  3. Prompts the user to pick a name and location for the file.
  4. Creates a new Excel workbook using XLWorkbook().
  5. Adds a worksheet containing all the data from our DataTable.
  6. Saves the file and provides success or error feedback to the user.

That’s all it takes for a basic export. The real power, however, comes from adding professional formatting.

GraphedGraphed

Build AI Agents for Marketing

Build virtual employees that run your go to market. Connect your data sources, deploy autonomous agents, and grow your company.

Watch Graphed demo video

Making Your Reports Look Good: Formatting with ClosedXML

A raw data dump is useful, but a well-formatted report is professional. ClosedXML makes styling a breeze. You can add the following code right before the workbook.SaveAs() line.

Style Headers

Make the header row stand out. This code selects the first row, makes it bold, and applies a background color.

// In your ExportToExcelButton_Click method, after adding the worksheet
var headerRow = worksheet.FirstRow(),
headerRow.Style.Font.Bold = true,
headerRow.Style.Fill.BackgroundColor = XLColor.LightGray,
headerRow.Style.Font.FontColor = XLColor.Black, 

Auto-Fit Column Widths

Nobody likes manually resizing columns. Let ClosedXML do it for you, ensuring all content is visible.

// This single line adjusts all columns to fit their content
worksheet.Columns().AdjustToContents(),

Freeze the Header Row

For long lists, keeping the headers visible as the user scrolls is a crucial usability feature.

// Freeze the first row so it stays visible while scrolling
worksheet.SheetView.FreezeRows(1),

The Legacy Method: Using Office Interop

For context, it’s helpful to understand the traditional Interop method. As mentioned, this approach is not recommended for new applications unless you need to automate a very specific Excel feature not available in other libraries.

Prerequisites

  • The client machine must have Microsoft Excel installed.
  • You must add a COM reference to the "Microsoft Excel Object Library" in Visual Studio.

Free PDF · the crash course

AI Agents for Marketing Crash Course

Learn how to deploy AI marketing agents across your go-to-market — the best tools, prompts, and workflows to turn your data into autonomous execution without writing code.

The Problem with Interop

The biggest challenge is resource management. Because you’re controlling the actual Excel application, you are responsible for closing every single COM object you create. Forgetting to do this will leave EXCEL.EXE processes running in the background, consuming memory long after your application has closed them.

The code is also more verbose, as you must manually loop through every single cell in your grid.

// A simplified example for demonstration only. AVOID THIS IN PRODUCTION if possible.
private void ExportWithInterop_Click(object sender, RoutedEventArgs e)
{
    Microsoft.Office.Interop.Excel.Application excelApp = null,
    Microsoft.Office.Interop.Excel.Workbook workbook = null,
    Microsoft.Office.Interop.Excel.Worksheet worksheet = null,

    try
    {
        excelApp = new Microsoft.Office.Interop.Excel.Application(),
        workbook = excelApp.Workbooks.Add(Type.Missing),
        worksheet = (Microsoft.Office.Interop.Excel.Worksheet)workbook.Worksheets[1],
        worksheet.Name = "Report",

        // Export Headers
        for (int i = 0, i < yourDataGrid.Columns.Count, i++)
        {
            worksheet.Cells[1, i + 1] = yourDataGrid.Columns[i].Header,
        }

        // Export Data Rows
        if (yourDataGrid.ItemsSource != null)
        {
            int rowIndex = 2,
            foreach (var item in yourDataGrid.ItemsSource)
            {
                for (int colIndex = 0, colIndex < yourDataGrid.Columns.Count, colIndex++)
                {
                    var column = yourDataGrid.Columns[colIndex] as DataGridBoundColumn,
                    var binding = column?.Binding as System.Windows.Data.Binding,
                    var propertyName = binding?.Path.Path ?? "",

                    var propertyInfo = item.GetType().GetProperty(propertyName),
                    if (propertyInfo != null)
                    {
                        var value = propertyInfo.GetValue(item),
                        worksheet.Cells[rowIndex, colIndex + 1] = value?.ToString() ?? "",
                    }
                }
                rowIndex++,
            }
        }

        // Show the excel app with the data (or save it)
        excelApp.Visible = true,
    }
    catch (Exception ex)
    {
        MessageBox.Show($"Error: {ex.Message}"),
    }
    finally
    {
        // CRITICAL FOR INTEROP: Release COM objects
        if (worksheet != null) System.Runtime.InteropServices.Marshal.ReleaseComObject(worksheet),
        if (workbook != null) System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook),
        if (excelApp != null) System.Runtime.InteropServices.Marshal.ReleaseComObject(excelApp),
    }
}

The verbosity and the absolute necessity of the finally block for cleanup make this method fragile compared to the simplicity of ClosedXML.

Final Thoughts

Providing an export-to-Excel feature can dramatically improve the utility of your C# applications. Using a modern library like ClosedXML is the clear best practice, it's faster, more reliable, and avoids dependencies on a user's local software. You can create professionally formatted, clean Excel reports with just a few lines of code.

While coding these custom reports offers precise control, the development and maintenance cycle can occupy valuable developer time. We built Graphed to automate precisely this kind of reporting work. Instead of manually exporting data and styling reports, we help you connect your data sources directly and generate live, interactive dashboards using simple natural language. It empowers your entire team to explore data and get immediate answers, all without writing a single line of export code.

Related Articles