Click here to Skip to main content
Click here to Skip to main content

Print a WinForms User Control

By , 20 Apr 2009
 

Introduction

A few weeks ago, I had a seemingly simple problem. My application has a complex user control, representing a report, and my client decided he wanted to be able to print it to a page. I thought, "how hard could that be?"

Background

After an hour vainly attempting to figure this out on my own, followed by queries to old colleagues, then some fruitless searching through this forum and others, I had found only a few hints and code snippets. I could print the control - but it was really tiny, and sitting in the corner of the page. Obviously, I needed to figure out how to scale the thing properly. So, I rolled up my sleeves and dove in ... and here we are.

A basic requirement before you will find this article helpful is to have a user control (or form) that makes sense to print to a full page. Some small controls will look absurd when expanded to a full page; some large ones that scroll off the screen will likely be illegible when shrunk to fit on a single sheet. But, the basic technique that I present should give you clues as to how you might treat those cases.

Using the code

Printing a scaled object actually turns out to be fairly simple ... once you already know how to do it.

The basic concept for all custom printing is to use the PrintPage event from a PrintDocument, probably owned by your form. Within your event handler, you can call a method of your custom control's class, where you can encapsulate any special needs that the control might have.

In my form, I have a property, CurrentReportControl, which points to the currently-viewed report, and so my PrintPage event handler looks like this:

/// <summary>
/// Print document wants to print a page.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void printDocument1_PrintPage(object sender, PrintPageEventArgs e)
{
  CurrentReportControl.PrintToGraphics(e.Graphics, e.MarginBounds);
}

The PrintPageEventArgs object provides a Graphics object on which to draw whatever you want, and it defines the page margins as well. I pass these to the PrintToGraphics() method of my custom control.

This method draws the control to a Bitmap, and then draws the bitmap to the Graphics object with the proper scaling. Care is taken to maximize the use of the printed page, without altering the aspect ratio of the control as viewed on the screen:

/// <summary>
/// Print the control's view to a Graphics object.
/// </summary>
/// <param name="graphics">Graphics object to draw on.</param>
/// <param name="bounds">Rectangle to print in.</param>
public void PrintToGraphics(Graphics graphics, Rectangle bounds)
{
  Bitmap bitmap = new Bitmap(this.Width, this.Height);
  this.DrawToBitmap(bitmap, new Rectangle(0, 0, bitmap.Width, bitmap.Height));
  Rectangle target = new Rectangle(0, 0, bounds.Width, bounds.Height);
  double xScale = (double)bitmap.Width / bounds.Width;
  double yScale = (double)bitmap.Height / bounds.Height;
  if (xScale < yScale)
    target.Width = (int)(xScale * target.Width / yScale);
  else
    target.Height = (int)(yScale * target.Height / xScale);
  graphics.PageUnit = GraphicsUnit.Display;
  graphics.DrawImage(bitmap, target);
}

Points of interest

An interesting topic that I found myself distracted by was the Graphics.PageUnit property, which defines various scalings for different graphical objects, such as display, printer, etc.

History

  • 1.0 - First release.

License

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

About the Author

tystent
Software Developer (Senior)
United States United States
Member
After seventeen years dinking around in electrical designs and software at a major defense contractor, I then spent six years making video slots do things they were never meant to do at a gaming company in Las Vegas. Now I'm a software consultant from home, since 2005.

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.
Search this forum  
    Spacing  Noise  Layout  Per page   
Question"Ported" to vb.netmemberGojiraDeMonstah14 Mar '13 - 12:07 
For those so inclined, I made a vb.net version:
 
Private Sub printDocument1_Printpage(sender As System.Object, e As System.Drawing.Printing.PrintPageEventArgs)
    Me.PrintToGraphics(e.Graphics, e.MarginBounds)
End Sub
 
Private Sub PrintToGraphics(graphics As Graphics, bounds As Rectangle)
    Dim bitmap As Bitmap = New Bitmap(Me.Width, Me.Height)
    Me.DrawToBitmap(bitmap, New Rectangle(0, 0, bounds.Width, bounds.Height))
    Dim target As Rectangle = New Rectangle(0, 0, bounds.Width, bounds.Height)
    Dim xScale As Double = CDbl(bitmap.Width / bounds.Width)
    Dim yScale As Double = CDbl(bitmap.Height / bounds.Height)
    If (xScale < yScale) Then
        target.Width = CInt(xScale * target.Width / yScale)
    Else
        target.Height = CInt(yScale & target.Height / xScale)
    End If
    graphics.PageUnit = GraphicsUnit.Display
    graphics.DrawImage(bitmap, target)
End Sub

GeneralMy vote of 5memberMember 780770625 Jun '12 - 5:47 
clear, simple & useful!
QuestionHow to print a user control which has scrollbar?memberbusbby11 Sep '10 - 16:30 
Hi tystent, your article is legible and easy to follow step by step. However, I have a question here, what if the user control has a scrollbar (vertical bar for example)? any clue to extent it to support pages by removing the scrollbar?
 
Thanks in advance.
AnswerRe: How to print a user control which has scrollbar?membertystent13 Sep '10 - 15:51 
Are you asking how you print a form that extends over more than one screen, thus requiring a scroll bar to show parts at a time, and thus how you would divide this into multiple printed pages as if the form were on many screens that were each being printed?
GeneralRe: How to print a user control which has scrollbar?memberbusbby14 Sep '10 - 0:22 
Tystent, thanks for you reply.
 
Yes. That's my question. If the user control content area is only one single page size, it's definitely OK by taking your solution. If it is larger than one single page, the user control uses scroll bar. I need to print the content area into multiple pages.
GeneralRe: How to print a user control which has scrollbar?membertystent4 Oct '10 - 13:38 
Since that's beyond the scope of this project, I'll just hypothesize here. Somehow you would have to let the form think it was able to draw all of itself without scrollbars on the screen. First by stretching out the form's size to fit all the content (beyond the borders of the actual screen), then (possibly) you would have to scale the entire form down to fit the screen. Either way, you would be getting rid of the need for scrollbars. Then, if you scaled it down, you would create printer pages similar scaled, so that you would parcel out sections of the whole form into these scaled printer pages. You might lose some resolution if you had to scale down, though.
 
I suppose this is why printer drivers and printing in general is so complicated - problems just like this.

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

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 21 Apr 2009
Article Copyright 2009 by tystent
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid