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

Speed Up Printing with the PrintPreviewDialog

Rate me:
Please Sign up or sign in to vote.
4.14/5 (9 votes)
30 Apr 2006CPOL2 min read 67.8K   1.6K   33   7
Supplies a custom PrintPreviewDialog that, at printing time, skips the passed printDocument object and prints from the previews.

Sample Image - image.jpg

Introduction

Have you ever had to do a printing system for your application and added all the computing logic into the printDocument? Well, in that case, I think you were exactly at the point I was when I thought of this custom PrintPreviewDialog.

So, what was the problem? Simple, the PrintPreviewDialog generates previews of the document it receives, and shows them to the user. Nothing wrong with this. When the user presser the Print button, the dialog starts generating again and draws all the pages again. This is useful when you deal with a database that is prone to changes every second. But when you have the user satisfied with what he sees on the preview and the job is a hard one (with all the database reading logic in it - let's say, with 100 pages and 3 seconds for a page), this tends to be a headache.

The solution

The solution is to inherit the PrintPreviewDialog, and make sure it prints from the previews generated previously. Sounds easy, but there is no other way to do that except using Reflection...

Behind the scenes

One of the main problems was to intercept the printButton clicks from the toolbar that is on the top of the dialog. Adding another Click handler to the toolbar does not help a bit because the old handler (from the base class) still does its job (prints from the PrintDocument). My solution was to remove the button from the toolbar and add my PrintButton that looked exactly like the previous one. Now, adding a new handle to the toolbar that checks if the button pressed was my new button was enough because the old button didn't have any chance of being clicked.

C#
public SpeedUpPrintPreviewDialog() : base()
{
    // we use reflection to be able to intercept
    // the print button click on the dialog
    // and do owe own fast printing
    Type t = typeof(PrintPreviewDialog);
    
    // first get the tool bar  
    FieldInfo fi = t.GetField("toolBar1", 
                   BindingFlags.Instance | 
                   BindingFlags.NonPublic);
    
    // then get the button
    FieldInfo fi2 = t.GetField("printButton", 
                    BindingFlags.Instance | 
                    BindingFlags.NonPublic);
    
    // set ower class variables
    ToolBar toolBar1 = (ToolBar)fi.GetValue(this);    
    ToolBarButton printButton = 
                 (ToolBarButton)fi2.GetValue(this);
       
    // hide the base printButton
    printButton.Visible = false;
    
     
    // create owr own prin button
    myPrintButton = new ToolBarButton();
    myPrintButton.ToolTipText = printButton.ToolTipText;
    myPrintButton.ImageIndex = 0;
    

    // recreate the base's toolbar buttons
    // with ower own print button
    ToolBarButton[] oldButtons = 
         new ToolBarButton[toolBar1.Buttons.Count-1];
    
    for(int i = 0 ; i < oldButtons.Length ; i++)
        oldButtons[i] = toolBar1.Buttons[i+1];
        
    toolBar1.Buttons.Clear();
    toolBar1.Buttons.Add(myPrintButton);
    
    for(int i = 0 ; i < oldButtons.Length ; i++)
    toolBar1.Buttons.Add(oldButtons[i]);
    
    // add another click handle for the toolbar
    toolBar1.ButtonClick += 
         new ToolBarButtonClickEventHandler(toolBar1_Click); 
    
    // initialize the inner print document
    innerPrintDocument = new PrintDocument();
    innerPrintDocument.BeginPrint += 
         new PrintEventHandler(innerPrintDocument_BeginPrint);
    innerPrintDocument.PrintPage += 
         new PrintPageEventHandler(innerPrintDocument_PrintPage);

}

The next step was to implement a custom prinDocument object that printed from the previews generated by the dialog. Obtaining the previews from the dialog was kind of hard because they are private members, so Reflection was necessary once again...

C#
private int NumberOfPages()
{
    Type t = typeof(PrintPreviewControl);
    FieldInfo pageInfo = t.GetField("pageInfo", 
              BindingFlags.Instance | BindingFlags.NonPublic);
    PreviewPageInfo[] infos = (PreviewPageInfo[]) 
              pageInfo.GetValue(this.PrintPreviewControl);
    return infos.Length;
}
    
private Image GetImageForPage(int pageNumber) 
{ 
    Type t = typeof(PrintPreviewControl);
    FieldInfo pageInfo = t.GetField("pageInfo", 
              BindingFlags.Instance | BindingFlags.NonPublic);
    PreviewPageInfo[] infos = (PreviewPageInfo[]) 
              pageInfo.GetValue(this.PrintPreviewControl);
    return infos[pageNumber].Image;
}

Now, having the number of pages in the preview, the images from the preview, and having a handle that knows when the user wants to print, the next and final step was to implement my printDocument to render each page from the preview.

C#
private void innerPrintDocument_PrintPage(object sender, PrintPageEventArgs e)
{
    // do owr drawing - print an image at the top of the page
    e.Graphics.DrawImage(GetImageForPage(
               innerPrintDocument_pageNumber), 0.0f, 0.0f);
    
    // do we still have more pages?
    if(innerPrintDocument_pageNumber == (NumberOfPages() - 1))
    e.HasMorePages = false; // no? - finish
    
    else 
    {
    innerPrintDocument_pageNumber++; // yes? - go on
    e.HasMorePages = true;
    }
}

Using the code

The control is easy to use, handle it like the PrintPreviewDialog. I hope somebody finds this of use, because it helped me.

License

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


Written By
Architect
Romania Romania
-

Comments and Discussions

 
GeneralReflection - not necessary for PrintPreviewDialog' controls Pin
Leonardo30011-Dec-09 2:52
Leonardo30011-Dec-09 2:52 
GeneralGreat solution - Thanks! Pin
b-k-w20-Aug-09 5:11
b-k-w20-Aug-09 5:11 
GeneralThnaks a lot on such a great work Pin
ronliao26-Dec-08 3:38
ronliao26-Dec-08 3:38 
GeneralGood article Pin
baranils21-Dec-08 10:41
baranils21-Dec-08 10:41 
Generalnot download Pin
liqiangsc27-Dec-07 17:52
liqiangsc27-Dec-07 17:52 
not download
GeneralWon't work in VS 2005 Pin
NCoder921411-May-06 9:20
NCoder921411-May-06 9:20 
GeneralRe: Won't work in VS 2005 Pin
NCoder921411-May-06 10:40
NCoder921411-May-06 10:40 

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.