Export GridView to Excel within an UpdatePanel

Export GridView to Excel within an UpdatePanel

There’s a ton of information online about exporting a DataGrid or GridView to Excel, but most variations do not consider the GridView may reside within an UpdatePanel.  It goes without saying, but I was disappointed when I recently dusted off my “Export GridView to Excel” code snippet and encountered a number of exceptions.  So I revisited a number of links and I collected a working solution.  If you need a “simple” way to export your GridView to Excel and you are using an UpdatePanel, I hope the following code finds you well:

protected void btnExport_Click(object sender, EventArgs e)
{
    // Reference your own GridView here
    if (AccountGrid.Rows.Count > 65535)
    {
        DisplayError("Export to Excel is not allowed" +
            "due to excessive number of rows.");
        return;
    }

    string filename = String.Format("Results_{0}_{1}.xls",
        DateTime.Today.Month.ToString(), DateTime.Today.Year.ToString());

    Response.Clear();
    Response.AddHeader("Content-Disposition", "attachment;filename=" + filename);
    Response.Charset = "";

    // SetCacheability doesn't seem to make a difference (see update)
    Response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache);  

    Response.ContentType = "application/vnd.xls";

    System.IO.StringWriter stringWriter = new System.IO.StringWriter();
    System.Web.UI.HtmlTextWriter htmlWriter = new HtmlTextWriter(stringWriter);

    // Replace all gridview controls with literals
    ClearControls(AccountGrid);

    // Throws exception: Control 'ComputerGrid' of type 'GridView'
    // must be placed inside a form tag with runat=server.
    // ComputerGrid.RenderControl(htmlWrite);

    // Alternate to ComputerGrid.RenderControl above
    System.Web.UI.HtmlControls.HtmlForm form
        = new System.Web.UI.HtmlControls.HtmlForm();
    Controls.Add(form);
    form.Controls.Add(AccountGrid);
    form.RenderControl(htmlWriter);

    Response.Write(stringWriter.ToString());
    Response.End();
}

private void ClearControls(Control control)
{
    for (int i = control.Controls.Count - 1; i >= 0; i--)
    {
        ClearControls(control.Controls[i]);
    }

    if (!(control is TableCell))
    {
        if (control.GetType().GetProperty("SelectedItem") != null)
        {
            LiteralControl literal = new LiteralControl();
            control.Parent.Controls.Add(literal);
            try
            {
                literal.Text =
                    (string)control.GetType().GetProperty("SelectedItem").
                        GetValue(control, null);
            }
            catch
            {}
            control.Parent.Controls.Remove(control);
        }
        else if (control.GetType().GetProperty("Text") != null)
        {
            LiteralControl literal = new LiteralControl();
            control.Parent.Controls.Add(literal);
            literal.Text =
                (string)control.GetType().GetProperty("Text").
                    GetValue(control, null);
            control.Parent.Controls.Remove(control);
        }
    }
    return;
}
 
Update: 7/30/2008

I previously noted that SetCacheability doesn’t seem to make a difference.  Well, I was right…until I deployed my code to a site behind SSL.  As it turns out, in order for Internet Explorer to open documents in Office (or any out-of-process, ActiveX document server), Internet Explorer must save the file to the local cache directory and ask the associated application to load the file by using IPersistFile::Load.

http://support.microsoft.com/default.aspx?scid=KB;EN-US;q316431&

If the file is not stored to disk, this operation fails. When Internet Explorer communicates with a secure Web site through SSL, Internet Explorer enforces any no-cache request. If the header or headers are present, Internet Explorer does not cache the file. Consequently, Office cannot open the file.

RESOLUTION: Web sites that want to allow this type of operation should remove the no-cache header or headers. In other words, comment out the following line of code particularly if you are running under SSL:

Response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache);

Additional Comments

Per Jinath Blog, if you are using an UpdatePanel, you may get a System.WebForms.PageRequestManagerParserErrorException exception.  The solution is to add a PostBackTrigger and give it’s ControlID as the excel export button’s ID or you can move your excel export button out side of the update panel.  I verified both options and they work great.  I ultimately went with the former option as such:

    ...
    </ContentTemplate>
    <Triggers>
        <asp:PostBackTrigger ControlID="btnExport" />
    </Triggers>
</asp:UpdatePanel>
...

Per ASPAlliance, you may encounter issues a number of issues which require the following solution.  Check out the link (and the comments) for more details if you get stuck.  I only encountered #1 on the list.

  1. You may get an exception which states your Control ‘Grid’ of type ‘GridView’ must be placed inside a form tag with runat=server.  I overcame this by dynamically adding a form to the page and then the GridView to the form before RenderContent().  This solution came per the aforementioned post’s comments.
  2. You may need to included the following page directive: EnableEventValidation=”false”.  I didn’t need to include this directive.
  3. You may need Override the VerifyRenderingInServerForm Method.  I didn’t need to do so because I added my GridView control to a “mocked” form.

Per Dipal Choksi, one can format the spreadsheet results in a generic manner by replacing all controls within the GridView with Literals.  This is reflected in the ClearControls() method above.  My prior implementation merely cleaned up the links associated with the sort functionality tied to the sortable headers.  This solution tackles all cells.

From: http://johnnycoder.com/blog/2008/07/25/export-gridview-to-excel-within-an-updatepanel/

原文地址:https://www.cnblogs.com/emanlee/p/1545578.html