giovedì, aprile 17, 2008

Scaricare una GridView ed aprirla con Excel

Vabbè.... per chi non ha voglia di cercare con Google (come Andrea), ecco come salvare ed aprire con Excel una GridView da una pagina Asp.Net


Nella codice della pagina asp.net:


protected void Button_Click(object sender, ImageClickEventArgs e)
{
this.RenderToHtml(GVDetails, "foo.xls");
}


private void RenderToHtml(GridView gv, string fileName)
{
_bypassNormalVRISF = true;
Response.Clear();
Response.ContentType = "application/vnd.ms-excel";
Response.AppendHeader("Content-Disposition", "attachment;filename=" + fileName);
StringWriter sw = new StringWriter();
HtmlTextWriter htw = new HtmlTextWriter(sw);
gv.RenderControl(htw);
Response.Write(sw.ToString());
Response.End();
}

private bool _bypassNormalVRISF = false;
public override void VerifyRenderingInServerForm(Control control)
{
if (_bypassNormalVRISF)
return;
else
base.VerifyRenderingInServerForm(control);
}


Per i dettagli su VerifyRenderingInServerForm vedere il sito MSDN. Comunque in 2 parole: molti (tutti?) dei controlli Asp.net devono essere creati al di sotto di <form runat="server">
Il metodo viene chiamato da questi controlli, tra cui GridView. L'implementazione standard di Page prevede che venga sollevata un eccezione se in quel momento la costruzione della pagina non è "al di sotto" di <form runat="server"> . Basta andare in override sul metodo e fargli fare una porcheria: saltare il controllo! Ovviamente è bene farlo solo quando serve: per questo c'è _bypassNormalVRISF.


[UPDATE: 29/10/2008]

Il pezzo di codice precedente funziona solo se nella GridView non sono presenti Control. Se è tutto testo OK ma se c'è anche un solo Control (ad esempio un Button), vengono sollevate eccezioni.
Soluzione: prima di eseguire il render in html, bisogna eliminare tutti i Control. Per fare questo il metodo riceve la lista delle colonne da eliminare. Inoltre, per non avere con il metodo VerifyRenderingInServerForm  basta copiare le righe della GridView in un oggetto Table creato al volo.

Codice:

public static void Export(string fileName, GridView gv, int[] skipColumns)
{
    List skipColumnsList = new List(skipColumns);
    using (StringWriter sw = new StringWriter())
    {
        using (HtmlTextWriter htw = new HtmlTextWriter(sw))
        {
            Table table = new Table();
            table.GridLines = GridLines.Both;

            if (gv.HeaderRow != null)
                table.Rows.Add(gv.HeaderRow);

            foreach (GridViewRow row in gv.Rows)                    
                table.Rows.Add(row);                    

            if (gv.FooterRow != null)
                table.Rows.Add(gv.FooterRow);

            foreach (TableRow row in table.Rows)
                RemoveCells(row, skipColumnsList);

            HttpContext.Current.Response.Clear();
            HttpContext.Current.Response.ContentType = "application/vnd.ms-excel";
            HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment;filename=" + fileName);
            table.RenderControl(htw);
            HttpContext.Current.Response.Write(sw.ToString());
            HttpContext.Current.Response.End();
        }
    }
}

private static void RemoveCells(TableRow row, List skipColumnsList)
{
    for (int i = row.Cells.Count - 1; i >= 0; i--)
        if (skipColumnsList.Contains(i))
            row.Cells.RemoveAt(i);
}


Nessun commento: