Click here to Skip to main content
15,889,034 members
Articles / Programming Languages / C#
Article

Extending C# PrintDialog Part II

Rate me:
Please Sign up or sign in to vote.
4.07/5 (7 votes)
18 Dec 2006CPOL3 min read 77.5K   2.7K   38   6
Printing Odd/Even pages in C#
Printing Odd/Even Pages

Introduction

C# provides a standard PrintDialog, which has all the basic print dialog functionality. Since it is declared as a sealed class, there is no way to extend it through C# native syntax. This article provides an alternate means to extend the functionality of the C# PrintDialog.

There are a lot of additional features that can be added to the common print dialog; one's imagination is the only limit. In this article, I will present a print dialog with an extended panel having: even/odd print page combobox, page setting button and an image.

Overview

PrintDialogEx serves as a wrapper to systems PrintDlg(common dialog), which uses P/Invoke methods to access the Win32 system's low-level APIs. Hook the dialog window mainproc and attach our extended user control panel when it receives a WM_INIT_DIALOG event notification. For a more detailed explanation, please refer to my previous article Extending C# PrintDialog Part I.

The main logic in achieving printing of odd/even pages is a general printing framework which, abstracts each print page into a C# class having common properties for a print page; included in these properties is a flag which indicates if the page should be printed or skipped during printing. The below figure depicts this concept:

Block Diagram

Generic Printing Framework

The framework was created with a general printing capability in mind; which means printing any sort of data namely: texts, images, tables having variable formatting/sizes and can accept any type of source data. For this article's purpose, only text printing is currently supported. However, the framework can be used as a base skeleton for user customizations and improvements.

Class Diagram

PrintDocumentEx is a customized print document object derived from System.Drawing.PrintDocument. It overrides and handles the following events: OnBeginPrint, OnEndPrint, OnPrintPage. These events are automatically called by the system. For a more detailed information, please refer to: Using PrintDocument.

OnBeginPrint - is called after the Print method is called and before the first page of the document prints. This is where we inject our code to create each PrintSection, layouts and calculate its size and add it to the next available PrintPage from PrintDocumentEx list container. Using a well-known design pattern called: Builder by Gamma, Helm, Johnson and Vlissides; to create different print document layout and presentations.

C#
protected override void OnBeginPrint(PrintEventArgs e) {
    base.OnBeginPrint(e);

    // reset current page index
    this.m_nCurrentPage = 0;

    // remove all previous print pages.
    this.m_oPages.Clear();
    if (this.DocBuilder != null) {
        // create the print document page layouts.
        this.DocBuilder.Build(this);
    }

    // initialize page skip flag attribute
    for(int nPage = 0; nPage < this.PageCount; nPage++) {
        Page oPage = this.GetPage(nPage);
        oPage.Skip = true;
        if ( this.m_bEvenPageOnly ) {
            // set page skip flag to false if page num is even
            oPage.Skip = ((nPage % 2) == 0) ? true : false;
        }
        else if ( this.m_bOddPageOnly  ) {
            // set page skip flag to false if page num is odd
            oPage.Skip = ((nPage % 2) == 0) ? false : true;
        }
        else {
            // prints all page
            oPage.Skip = false;
        }
    }
}

The document builder creates the appropriate concrete section object based on the print data type. After all the print pages initialization, we iterate all print pages and set its skipped flag value to true or false, depending on our PrintDocumentEx OddPageOnly or EvenPageOnly property value.

OnPrintPage - is called before a page prints. Here we iterate through our print page container list and manually draw each section contained on each page to a GDI graphics object(PrintPageEventArgs.Graphics).

C#
protected override void OnPrintPage(PrintPageEventArgs e) 
{
    try {
        base.OnPrintPage(e);

        // get the page print area
        Graphics gdiPage = e.Graphics;
        float leftMargin = e.MarginBounds.Left;
        float topMargin = e.MarginBounds.Top;
        Rectangle oArea = e.MarginBounds;

        // get the next page, labelled for printing.
        Page oPage = this.GetPage(this.m_nCurrentPage++);
        while( oPage.Skip && (this.m_nCurrentPage < this.PageCount) ) {
            oPage = this.GetPage(this.m_nCurrentPage++);
        }

        if ( (null != oPage) && !oPage.Skip ) {
            gdiPage.DrawString("Page " + this.m_nCurrentPage, 
			new Font("Verdana", 10), Brushes.Black, 
                leftMargin, 0 );

            oPage.OnPrintPage(gdiPage, this.m_oPrintArea );
        }

        // checks if there are more pages to print
        e.HasMorePages = this.HasMorePages();
    }
    catch { // handle all unknown errors during printing.
        e.HasMorePages = false;
    }

} // OnPrintPage

OnEndPrint - is called when the last page of the document has printed. nothing fancy here, we just removed all pages contained in our list.

Using the Code

Client application needs only to create a PrintDialogEx, associate it to an instance of PrintDocumentEx before calling its ShowDialog(). By default, we can set to print odd/even pages by setting the PrintDocumentEx's OddPageOnly or EvenPageOnly to true. Below is a sample code snippet to do this:

C#
PrintDialogEx oPrintDlg = new PrintDialogEx();

PrintDocumentEx oDocument = PrintDocumentEx();
// set to print odd pages only.
oDocument.OddPageOnly = true;

// set the dialogs owner window(optional)
// parent handle should be a handle to a window Form
oPrintDlg.Parent = this.Handle;
// associate this dialog to a print document instance.
oPrintDlg.Document = oDocument;

// Shows the print dialog extended control panel by default.
oPrintDlg.UseEXDialog = true;
// display the print dialog with extended panel control
DialogResult nResult = oPrintDlg.ShowDialog();

Point of Interests

  • Represent any source print data in an XML form

References

  1. Printing Overview, MSDN Documentation
  2. Extend the Common Dialog Boxes, MSDN Tutorials

History

  • 2006.12.18 - Original version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Singapore Singapore
A graduate in Bachelor of Science in Computer Engineering from the Philippines. His love for software programming/design/patterns started in his college days when he found out that he possesses above average skill in computer programming. He started his career as a computer instructor for a year, then shifts to work as a software design engineer in one of the renowned Japanese company in the Philippines. After almost 5 years working in that company he got an opportunity to work in japan were he now currently lives and work since 2003.

Comments and Discussions

 
BugWin 8.1 Issue Pin
WiiMaxx21-Aug-14 21:24
WiiMaxx21-Aug-14 21:24 
Your code doesn't seems to work on my Win8.1 PC
i use VS2013

if i press the print button (button1)i get immediately "Cancel button click"
without an Print dialog.

what do i need to change to get your code working Confused | :confused:
GeneralMy vote of 4 Pin
polczym25-Aug-11 22:21
polczym25-Aug-11 22:21 
GeneralInstantly Printing Pin
asif rehman baber17-Dec-09 20:18
asif rehman baber17-Dec-09 20:18 
QuestionExtending PrintDialog in VC++ Pin
Member 37288416-Dec-08 0:02
Member 37288416-Dec-08 0:02 
GeneralIs it an unmanaged Code Pin
Member 41803746-Mar-08 23:44
Member 41803746-Mar-08 23:44 
GeneralPrintPageEventArg.Graphics question Pin
Wolfram Steinke11-Apr-07 13:14
Wolfram Steinke11-Apr-07 13:14 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.