Search

Export ASP.NET DataGrid to Excel

0 views

Exporting a DataGrid to Excel is a feature many ASP.NET Web Forms developers need to implement for reports, data analysis, and offline processing. The process looks simple, but the details - especially when your grid contains complex controls - can trip up even seasoned programmers. This guide walks you through the entire workflow, from preparing the grid to writing clean, robust server‑side code that produces a spreadsheet users can open with any recent version of Excel.

Preparing Your DataGrid for Export

Before any export code runs, your DataGrid must be ready to render as plain HTML. A DataGrid that supports sorting, paging, or contains templated columns can generate a lot of server‑side controls that Excel can't interpret directly. The first step is to remove or replace those controls so that the grid’s output contains only literal text and simple HTML markup.

Begin by reviewing the grid’s columns. A standard DataGrid might look like this in markup:

Prompt
<asp:DataGrid ID="dgEmployees" runat="server" AutoGenerateColumns="False"></p> <p> <Columns></p> <p> <asp:BoundColumn DataField="EmployeeID" HeaderText="ID" /></p> <p> <asp:BoundColumn DataField="LastName" HeaderText="Last Name" /></p> <p> <asp:BoundColumn DataField="FirstName" HeaderText="First Name" /></p> <p> <asp:TemplateColumn HeaderText="Actions"></p> <p> <ItemTemplate></p> <p> <asp:LinkButton ID="btnEdit" runat="server" Text="Edit" CommandName="Edit" /></p> <p> </ItemTemplate></p> <p> </asp:TemplateColumn></p> <p> </Columns></p> <p></asp:DataGrid>

Notice the TemplateColumn with a LinkButton. When the grid renders, ASP.NET creates a button control for each row, but that button isn’t just a string of text. Excel will ignore it or misinterpret it. To avoid this, you should replace interactive controls with static representations. For example, you could change the LinkButton to a plain text string like “Edit” or “ - ” if the action is not needed for the export.

Another common pitfall is paging. If the grid shows only a subset of rows on the screen, the export will naturally send only those rows to the user. Decide whether you want to export the current page or the entire dataset. If you opt for all rows, bypass paging before rendering the grid, or rebuild the DataGrid with the full data set.

When the grid is clean, its RenderControl method will produce valid HTML that Excel can open as a spreadsheet. That’s the foundation for the next step: wrapping the HTML in an HTTP response that signals a file download.

Building the Export Button and Response Headers

Once the grid is ready, expose a button on the page that users click to trigger the export. The button’s click handler will handle everything: clearing the response, setting headers, rendering the grid, and ending the page lifecycle.

The core of the handler looks like this:

Prompt
protected void btnExport_Click(object sender, EventArgs e)</p> <p>{</p> <p> // 1. Reset the response to remove any existing content</p> <p> Response.Clear();</p> <p> // 2. Define a filename and MIME type for an Excel 97+ file</p> <p> Response.AddHeader("content-disposition", "attachment;filename=Employees.xls");</p> <p> Response.Charset = "";</p> <p> Response.ContentType = "application/vnd.ms-excel";</p> <p> // 3. Create a StringWriter and HtmlTextWriter to capture the grid output</p> <p> StringWriter stringWriter = new StringWriter();</p> <p> HtmlTextWriter htmlWriter = new HtmlTextWriter(stringWriter);</p> <p> // 4. Render the DataGrid into the writer</p> <p> dgEmployees.RenderControl(htmlWriter);</p> <p> // 5. Write the rendered HTML to the response stream</p> <p> Response.Write(stringWriter.ToString());</p> <p> // 6. Flush and end the response so ASP.NET doesn’t append additional markup</p> <p> Response.End();</p> <p>}

Each step has a purpose. Clearing the response guarantees that no residual markup from the page’s rendering pipeline interferes with the exported file. The content-disposition header instructs browsers to present a file download dialog with the specified name. Setting the ContentType to application/vnd.ms-excel tells the client that the data is an Excel file. Even though the content is really HTML, modern browsers and Excel handle the format gracefully.

Creating a StringWriter and HtmlTextWriter gives you a lightweight way to capture the grid’s HTML. The RenderControl method walks the grid’s control tree, emitting the resulting markup to the writer. Finally, the writer’s string is sent to the response and the page is terminated. Using Response.End() ensures that no other controls or scripts run after the export, preventing duplicate or corrupted data.

When testing, make sure the browser accepts the MIME type and prompts for download. Some browsers may treat the file as a generic document; double‑clicking the downloaded file should open it in Excel. If the file opens in a web browser instead, double‑check that the header is correctly spelled and that no other code writes to the response before the export logic.

Replacing Complex Controls and Generating Excel‑Friendly Output

Complex controls inside a DataGrid, such as drop‑down lists, checkboxes, or user controls, can throw off the rendering process. Even though RenderControl produces markup, the presence of interactive elements can produce output that Excel either ignores or misinterprets. The safest approach is to strip or replace these controls with literal values before rendering.

A robust solution uses reflection to inspect each cell’s controls at runtime. The algorithm proceeds as follows:

Step 1: Enumerate all table cells in the DataGrid. Each DataGridItem contains a collection of TableCell objects. Loop through every cell in every row.

Step 2: For each cell, inspect its child controls. If the cell contains more than one control, decide whether to combine their textual representations or keep them separate. Most often, you’ll replace a control with its Text or SelectedItem value.

Step 3: Handle controls that expose a Text property. TextBox, Button, and templated columns usually have this property. Use reflection to read the property and replace the control with a LiteralControl containing that text.

Step 4: Handle controls that expose a SelectedItem property. Drop‑down lists and list controls fall into this category. Retrieve the SelectedItem and, if it exists, insert its text into a new literal.

Step 5: Preserve simple table cells. If a cell contains only static text or a single literal, leave it untouched. Avoid changing the visual layout of the grid for users.

Below is a concise helper method that performs the reflection logic described above. Call it just before rendering the grid in the export handler:

Prompt
private void CleanGridForExport(DataGrid grid)</p> <p>{</p> <p> foreach (DataGridItem item in grid.Items)</p> <p> {</p> <p> foreach (TableCell cell in item.Cells)</p> <p> {</p> <p> // Skip cells that contain only literal text</p> <p> if (cell.Controls.Count == 1 && cell.Controls[0] is LiteralControl)</p> <p> continue;</p> <p> // Replace each non-literal control</p> <p> for (int i = 0; i <p> {</p> <p> Control ctrl = cell.Controls[i];</p> <p> string text = null;</p> <p> // Use reflection to look for Text or SelectedItem properties</p> <p> var textProp = ctrl.GetType().GetProperty("Text");</p> <p> if (textProp != null)</p> <p> {</p> <p> text = textProp.GetValue(ctrl, null) as string;</p> <p> }</p> <p> else</p> <p> {</p> <p> var selProp = ctrl.GetType().GetProperty("SelectedItem");</p> <p> if (selProp != null)</p> <p> {</p> <p> var selected = selProp.GetValue(ctrl, null);</p> <p> if (selected != null)</p> <p> {</p> <p> var selTextProp = selected.GetType().GetProperty("Text");</p> <p> if (selTextProp != null)</p> <p> text = selTextProp.GetValue(selected, null) as string;</p> <p> }</p> <p> }</p> <p> }</p> <p> // If we found text, replace the control</p> <p> if (!string.IsNullOrEmpty(text))</p> <p> {</p> <p> cell.Controls.RemoveAt(i);</p> <p> cell.Controls.Add(new LiteralControl(text));</p> <p> }</p> <p> }</p> <p> }</p> <p> }</p> <p>}

Call CleanGridForExport(dgEmployees); right after you bind data and before you render the grid. This guarantees that only plain text appears in the exported file. Because the cleaning routine runs on the server side, users never see the intermediate state; they only receive the final spreadsheet.

While the reflection-based approach covers most common controls, you may encounter custom user controls that expose different properties. Extend the helper by adding custom logic for those controls. For example, if you have a CustomDatePicker that exposes a DisplayValue property, add a conditional check that pulls that value.

Finally, if you want to tweak the appearance of the spreadsheet, add CSS styles to the grid’s header or cell tags before rendering. Excel interprets inline styles, so you can set background colors, fonts, or borders. Insert a <style> block in the page’s <head> and reference the style classes in the grid. When the grid renders, those styles become part of the HTML that Excel opens, giving you control over the look of the exported sheet.

Suggest a Correction

Found an error or have a suggestion? Let us know and we'll review it.

Share this article

Comments (0)

Please sign in to leave a comment.

No comments yet. Be the first to comment!

Related Articles