Export a Gridview in iTextSharp

PDF reports are a wonderful way of delivering content to users. And there are a lot of great tools out there to create them. The tool I use the most is iTextSharp, the .Net port of the Java iText PDF creation and manipulation tool.

One the most popular controls in ASP.Net to display data is the GridView. In this entry I will discuss one method of converting a Gridview to PDF in one quite simple step. I will even discuss how to take it one step further.

The Render Method

To make it easy to convert from GridView on a web page to a GridView on PDF we will make use of the Render method on the control. The render method is the function on pretty well each ASP.Net server control that creates the HTML you see on the browser.

I can use of that method to generate PDF, and I can do it without much code!

iText XHTML Parser

Part of the wonderful toolkit that is iTextSharp (& iText) is the ability to convert XHTML to PDF. While it is not perfect this is a great way to convert a HTML output into PDF.

The Code

So now the bit you are waiting for, the code. How do you to this?

The general process is that we setup the iText HTML parsing and CSS . Then generate the HTML from the Gridview, splice in a bit of heading and footing and any other content we want on the PDF. Pass the HTML to iText and a PDF output will be created.

        Dim sw As StringWriter = New StringWriter()
        Dim hw As HtmlTextWriter = New HtmlTextWriter(sw)
        Dim frm As HtmlForm = New HtmlForm()
        sw.Write("<!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.0 Transitional//EN"" ""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\""><html><head></head><body>")
        sw.Write("<p>A Sample Grid output to PDF. IText will automatically split this over pages too</p>")
        gridView.AllowSorting = False
        gridView.AllowPaging = False
        gridView.HeaderRow.Visible = True
        gridView.BorderWidth = 0
        gridView.RenderControl(hw)
        sw.Write("<p>And that's all there is to it!</p>)
        sw.Write("</body></html>")

        Dim ms As MemoryStream = New MemoryStream()
        Dim sr As StreamWriter = New StreamWriter(ms)
        sr.Write(sw)
        sr.Flush()
        Dim ms2 As MemoryStream = New MemoryStream(ms.GetBuffer())
        ms.Close()
        Dim pdfDoc As Document = New Document()
        pdfDoc.SetPageSize(PageSize.A4)
        pdfDoc.SetMargins(10.0F, 10.0F, 24.0F, 24.0F)

That is main bulk of the code. There is lot of flipping of streams, which necessary because we write the XHTML out to a stream and then that needs to  read back in by iTextSharp.

We then need to create the iTextSharp XHtml parser. In the later versions of iTextSharp there is a new properly maintained XHTML parser. Do be sure do use this one rather than the older simpleparser

   Private Shared Function CreateXMLParser(ByVal pRequest As HttpRequest, ByVal pdfDoc As Document, ByVal pdfWriter As PdfWriter) As XMLParser
        Dim htmlContext As HtmlPipelineContext = New HtmlPipelineContext(Nothing)
        htmlContext.SetTagFactory(Tags.GetHtmlTagProcessorFactory())
        htmlContext.SetImageProvider(New myAbstractImageProvider(pRequest))

        Dim cssResolver As ICSSResolver = XMLWorkerHelper.GetInstance().GetDefaultCssResolver(False)

        Dim pipeline As IPipeline = New CssResolverPipeline(cssResolver, New HtmlPipeline(htmlContext, New PdfWriterPipeline(pdfDoc, pdfWriter)))
        Dim worker As XMLWorker = New XMLWorker(pipeline, True)
        Dim p As XMLParser = New XMLParser(worker)
        ' add in CSS
        Dim CSSstrm As StreamReader = New StreamReader(pRequest.MapPath("/Styles/mystyles.css"))
        cssResolver.AddCss(XMLWorkerHelper.GetCSS(CSSstrm.BaseStream))
        Return p
    End Function

Now that is done, and using a CSS of my creating ( A bit about that below). We then parse the stream through and return the PDF created as the response

        Response.Clear()
        Response.ContentType = "application/pdf"

        Response.AddHeader("content-disposition", "attachment;filename=Export.pdf")
        Response.Cache.SetCacheability(HttpCacheability.NoCache)

        pdfDoc.Open()

        Dim xmlwrk As XMLParser = CreateXMLParser(Request, pdfDoc, pdfa)
        xmlwrk.Parse(ms2)

        pdfa.Flush()
        pdfDoc.Close()
        Response.End()

There is a caveat to all this and that is that iTextSharp is not yet up to HTML 5 and the CSS handling is basic. iTextSharp doesn’t understand CSS ¬†features like:

        div.TBL table tr {
            border-left: 2px solid red;
        }

You will need to specify a class on the tr element to get this to work by iTextSharp.

Conclusion

And that’s all there is to it.

This is greatly simplified the output to a grid to PDF and thanks to the gridview render method. You can, ofcourse, do it yourself if you have advanced needs. And in a further post I will show how you can splice in your own rows into a gridview output.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.