views:

647

answers:

6

What is the best way to export a gridview into an Excel spreadsheet? This seems easy

except that my Gridview doesn't have an export attribute. What is the quickest way to do this?

A: 

This library for .net has worked very well for our use cases.

This library allows you to generate Excel Workbooks using XML, it is built 100% in C# and does not requires Excel installed at all to generate the files. It exposes a simple object model to generate the XML Workbooks.

There's no built-in integration with a GridView control, but writing a generic adapter is easy enough and would be reusable in other projects.

Ken Browning
+1  A: 

There's probably something out there for this, but if you want to do it yourself you could just write some code that walks the GridView.Rows collection, and then the GridViewRow.Cells collection inside of that.

It should be pretty easy to build a CSV file from there, and Excel could read it no problem.

CSV files are just text files with values inside of quotes, seperated by commas. Like this:

"value", "value", "value"
"value", "value", "value"

You can just pop Notepad open and build one by hand to try it out.

Brian MacKay
A: 
Private exportToExcel As Boolean = False

Private Sub LoadInExcel()
    Me.Response.ClearContent()
    Me.Response.AddHeader("content-disposition", "attachment; filename=MyFile.xls")
    Me.Response.ContentType = "application/ms-excel"
    Dim sw1 As New IO.StringWriter
    Dim htw1 As HtmlTextWriter = New HtmlTextWriter(sw1)
    GridView1.RenderControl(htw1)
    Response.Write(sw1.ToString())
    Response.End()
End Sub

Public Overrides Sub VerifyRenderingInServerForm(ByVal control As Control)
    ' Confirms that an HtmlForm control is rendered for the specified ASP.NET
    ' server control at run time.
End Sub

Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
    If exportToExcel Then
        LoadInExcel()
    End If

    MyBase.Render(writer)
End Sub

Protected Sub btnPrint_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnPrint.Click
    exportToExcel = True
End Sub

You must have excel installed and reference the Office interop libraries in your project. Add:

Imports Microsoft.Office.Core, Imports Microsoft.Office.Interop

The solution above takes the gridview and pulls the html out of it. Then writes it to excel. The html coming from the grid will include style attributes such as padding & color. It will also make sortable column headings look like links. When I used this I wrote a custom parser to strip all the unwanted styling out to give me just the raw data. I will leave that task up to you since it is specific to each grid.

It is very important that you include the override to VerifyRenderingInServerForm, even though there is not any code inside of it.

Bradley
i like where you are going with this. however, I'm not allowed to import microsoft.office.core
Eric
where can i get the microsoft office files?
Eric
@Eric - You can get them by having Office installed on the same machine. However, it should be noted that running Office on a server generally isn't considered to be a best practice.
Rob
1. You don't need Microsoft Office on the machine for this method.2. Never run non-SharePoint/non-MOSS Office components on the server, it's a licensing violation and a performance risk.
andrewbadera
I do agree that installing Office on a production server is bad practice. Sometimes we bend the rules to get the results we need in the time contraints we have. The XML solution above is the best answer, but creating templates and parsing XML can be cumbersome.
Bradley
+1  A: 

I've done this several times. Excel has a XML version. It ends up with the .xml extension, but you can just change the file's extension to .xls and the XML formatted file will open in excel just fine.

The biggest hurdle of this approach is the excel XML format. I usually create an excel file in excel in the approximate format that I desire. I then save the Excel file to XML format, and open it up in a text editor.

I usually create a template file from this Excel sample page. Then when I am exporting the information in the Gridview, I only have to create the xml for the section that contains the cells I plan on populating, I just prepend, and append the text already in the template file.

Once you open up the xml formatted excel file, you'll figure out the needed XML relatively easily. The hardest part to understand is the way the cells reference the formatting options, which are at the top of the XML file.

Good luck, let me know if you need more clarification.

Edit: You will only need to create the template excel file once, just to get a feel for the needed xml that you'll need to generate. Once you've generated the xml use the following code to send it to the user:

string fileName = "ExportedFile.xls";
Response.Clear();
Response.Buffer = true;
Response.ContentType = "text/xml";
Response.AddHeader("Content-Disposition", "attachment; filename=" + fileName);
ExportToExcel(HttpContext.Current.Response.OutputStream, testUID);
Response.End();



public static void ExportToExcel(Stream outputStream)
{
    XmlTextWriter xmlSink = new XmlTextWriter(outputStream, Encoding.Default);

    //ExcelHeaderString and ExcelStylesString are from the template
    xmlSink.WriteRaw(ExcelHeaderString);
    xmlSink.WriteRaw(ExcelStylesString);

    //write your elements here
    xmlSink.WriteElement("YourElements");

    //ExcelFooterString is from the template
    xmlSink.WriteRaw(ExcelFooterString);
}
Chris
my issue with this is that I would have to do this at every machine right? I'd have to create an excel file at every machine. This is app will be used company wide.
Eric
I thought you would program this into the code that contains the GridView. I am a little confused by your statement. Are you creating a web-based application or a desktop application?
Chris
yes. that is correct. i am going to attempt to program this. This is a web-based application. I may be the one confused. but you said you have to normally create an excel file in excel. I would have to do that on every computer that this app is used right?
Eric
No, I was telling you to first create a template excel file just so that you could get a feel for the XML format needed. I would then statically store the header and footer string into your program so that you can output those on demand. All the other files will be generated dynamically. I posted some sample code.
Chris
A: 

thanks its good

sugriv
A: 

I used CarlosAg.ExcelXmlWriter link.

I looped through all GridViews HeaderCells and then through all rows. The only thing is that if you allow paging and you've more than one page you have to set the PageSize to a high value (I set to 10000000) then DataBind the GridView again and do your work. Afterwards set the old PageSize value back. If someone knows a better solution, you're welcome.

EDIT: The try/catch is there because for some reason it is not possible to check the control type and then cast to Label or LinkButton ==> control.GetType().

Here's my code.

 public static Workbook CreateWorkbook(GridView gridView)
    {
        int pageSize = gridView.PageSize;
        gridView.PageSize = 10000000;
        gridView.DataBind();

        Workbook workbook = new Workbook();
        Worksheet sheet = workbook.Worksheets.Add("Export");

        WorksheetStyle style = workbook.Styles.Add("headerStyle");
        style.Font.Bold = true;
        style = workbook.Styles.Add("defaultStyle");
        style.Alignment.WrapText = true;
        style = workbook.Styles.Add("infoStyle");
        style.Font.Color = "Red";
        style.Font.Bold = true;

        sheet.Table.Rows.Add(new WorksheetRow());

        WorksheetRow headerRow = new WorksheetRow();
        foreach (DataControlFieldHeaderCell cell in gridView.HeaderRow.Cells)
        {
            if (!string.IsNullOrEmpty(cell.Text))
                headerRow.Cells.Add(cell.Text, DataType.String, "headerStyle");
            else
                foreach (Control control in cell.Controls)
                {
                    LinkButton linkButton = new LinkButton();
                    try
                    {
                        linkButton = (LinkButton)control;
                    }
                    catch { }

                    if (!string.IsNullOrEmpty(linkButton.Text))
                        headerRow.Cells.Add(linkButton.Text, DataType.String, "headerStyle");
                    else
                    {
                        Label label = new Label();
                        try
                        {
                            label = (Label)control;
                        }
                        catch { }
                        if (!string.IsNullOrEmpty(label.Text))
                            headerRow.Cells.Add(label.Text, DataType.String, "headerStyle");
                    }
                }
        }

        sheet.Table.Rows.Add(headerRow);

        foreach (GridViewRow row in gridView.Rows)
        {
            WorksheetRow wrow = new WorksheetRow();
            foreach (TableCell cell in row.Cells)
            {
                foreach (Control control in cell.Controls)
                {
                    if (control.GetType() == typeof(Label))
                    {
                        wrow.Cells.Add(((Label)control).Text, DataType.String, "defaultStyle");
                    }
                }
            }
            sheet.Table.Rows.Add(wrow);
        }

        gridView.PageSize = pageSize;

        return workbook;
    }
Kosta