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