MigraDoc: Show Progress While Rendering a Document

Let’s face it: as of today it sometimes takes a few seconds to create a PDF for a MigraDoc document, especially if the document contains many tables.
A nice progress bar will prevent users from pressing Ctrl+Alt+Del to kill a presumably hung application. I’ll show you how this can be done.

You can render a PDF document from MigraDoc with one line of code:

// Classical rendering without progress indicator.
// Layout and render document to PDF
pdfRenderer.RenderDocument();

In order to get feedback for the progress indicator, we will need a few lines more.

Creating the PDF file from MigraDoc requires two steps. In step 1, MigraDoc prepares the document, calculates the sizes and positions of everything.
To show progress, you just have to register a callback routine.

// Alternative rendering with progress indicator.
// Set a callback for phase 1.
pdfRenderer.DocumentRenderer.PrepareDocumentProgress
    += PrepareDocumentProgress;
// Now start phase 1: Preparing pages
// (i.e. calculate the layout).
pdfRenderer.PrepareRenderPages();

My sample is a console application and the progress indicator simply writes a percent value into the console window.

// Sample progress callback,
// called while preparing a document
// (while MigraDoc measures items,
// creates line breaks, page breaks etc.).
private static void PrepareDocumentProgress
    (object sender, 
     DocumentRenderer.PrepareDocumentProgressEventArgs e)
{
    int percent = 
        e.Value * 100 / e.Maximum;
    if (percent != lastPercentHack)
    {
        Console.Write("rPreparing "
            + percent + "%");
    }
}
private static int lastPercentHack = -1;

When the document is prepared, the number of pages is known. Now we just make a loop that creates the pages one by one and allows to indicate the progress after every page.

// Now phase 2: create the PDF pages.
Console.WriteLine("rnRendering document ...");

int pages = pdfRenderer.DocumentRenderer.FormattedDocument.PageCount;
for (int i = 1; i <= pages; ++i)
{
    var page = pdfRenderer.PdfDocument.AddPage();
    Console.Write("rRendering page " + i + "/" + pages);

    PageInfo pageInfo = pdfRenderer.DocumentRenderer.FormattedDocument.GetPageInfo(i);
    page.Width = pageInfo.Width;
    page.Height = pageInfo.Height;
    page.Orientation = pageInfo.Orientation;

    using (XGraphics gfx = XGraphics.FromPdfPage(page))
    {
        gfx.MUH = pdfRenderer.Unicode ? PdfFontEncoding.Unicode : PdfFontEncoding.WinAnsi;
        gfx.MFEH = pdfRenderer.FontEmbedding;
        pdfRenderer.DocumentRenderer.RenderPage(gfx, i);
    }
}
Console.WriteLine("rnSaving document ...");

I already wrote that my sample was written as a console application. Real applications will use WPF or WinForms or whatever. Each framework will offer different methods to indicate progress but that is beyond the scope of this post.

5 thoughts on “MigraDoc: Show Progress While Rendering a Document”

  1. This is very useful, thank you. Is there a way of cancelling the render if my user mistakenly selects data which causes a very long construction? I would like to add a cancel button next to the progress bar.

    1. Progress during PDF generation can be done with VB.NET and should also be possible with other .NET languages. VB.NET just uses a different syntax. What do you mean with loading progress?

Leave a Reply

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