Combine Multiple PrintDocuments [C#]

This example shows how to combine two or more PrintDocuments in­to a single PrintDocument. I created a class MultiPrintDocu­ment derived from PrintDocument. Its constructor takes an array of PrintDocument instances as a parameter.

The usage of the MultiPrintDocument class could be like this.

// suppose we need to join 3 PrintDocument instances doc1, doc2 and doc3
MultiPrintDocument multiDoc;
multiDoc = new MultiPrintDocument(new PrintDocument[] { doc1, doc2, doc3 });

MultiPrintDocument overrides protected methods OnBeginPrint, OnQueryPageSet­tings and OnPrintPage. The overridden methods call the corresponding methods of the child documents. Note that reflection must be used to call the protected methods of child documents.

OnBeginPrint method is called before the first page of the document is printed. The overridden OnBeginPrint method resets the current document index.

OnQueryPageSet­tings method is called immediately before printing each page and is used for getting the PageSettings of the printed page (e.g. to check whether the page orientation is landscape or portrait). The overridden method calls OnQueryPageSettings of the current child document.

OnPrintPage is called to print a page. The overridden method calls OnPrintPage of the current child document. If it is the last page of the document, it increments the current document index and returns a value indicating that there are still other pages to print.

This is the code of the MultiPrintDocument class.

using System.Drawing.Printing;
using System.Reflection;

public class MultiPrintDocument : PrintDocument
  private PrintDocument[] _documents;
  private int _docIndex;
  private PrintEventArgs _args;

  // constructors
  public MultiPrintDocument(PrintDocument document1, PrintDocument document2)
    _documents = new PrintDocument[] { document1, document2 };

  public MultiPrintDocument(PrintDocument[] documents)
    _documents = documents;

  // overidden methods
  protected override void OnBeginPrint(PrintEventArgs e)
    if (_documents.Length == 0)
      e.Cancel = true;

    if (e.Cancel) return;

    _args = e;
    _docIndex = 0;  // reset current document index
    CallMethod(_documents[_docIndex], "OnBeginPrint", e);

  protected override void OnQueryPageSettings(QueryPageSettingsEventArgs e)
    e.PageSettings = _documents[_docIndex].DefaultPageSettings;
    CallMethod(_documents[_docIndex], "OnQueryPageSettings", e);

  protected override void OnPrintPage(PrintPageEventArgs e)
    CallMethod(_documents[_docIndex], "OnPrintPage", e);
    if (e.Cancel) return;
    if (!e.HasMorePages)
      CallMethod(_documents[_docIndex], "OnEndPrint", _args);
      if (_args.Cancel) return;
      _docIndex++;  // increments the current document index

      if (_docIndex < _documents.Length)
        // says that it has more pages (in others documents)
        e.HasMorePages = true;
        CallMethod(_documents[_docIndex], "OnBeginPrint", _args);

  // use reflection to call protected methods of child documents
  private void CallMethod(PrintDocument document, string methodName, object args)
      BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic,
      null, document, new object[] { args });

See also