Click here to Skip to main content
Licence CPOL
First Posted 30 Apr 2006
Views 44,674
Bookmarked 31 times

Speed Up Printing with the PrintPreviewDialog

By | 30 Apr 2006 | Article
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.

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...

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.

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)

About the Author

Stanciu Vlad

Architect

Romania Romania

Member

-

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralReflection - not necessary for PrintPreviewDialog' controls PinmemberLeonardo30012:52 1 Dec '09  
GeneralGreat solution - Thanks! Pinmemberb-k-w5:11 20 Aug '09  
GeneralThnaks a lot on such a great work Pinmemberronliao3:38 26 Dec '08  
GeneralGood article Pinmemberbaranils10:41 21 Dec '08  
Generalnot download Pinmemberliqiangsc17:52 27 Dec '07  
GeneralWon't work in VS 2005 PinmemberNCoder92149:20 11 May '06  
GeneralRe: Won't work in VS 2005 PinmemberNCoder921410:40 11 May '06  

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

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

Permalink | Advertise | Privacy | Mobile
Web04 | 2.5.120517.1 | Last Updated 1 May 2006
Article Copyright 2006 by Stanciu Vlad
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid