Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Form Print Control

3.71/5 (7 votes)
21 Jan 2009CPOL7 min read 11   7.3K  
An extender control to make printing a form quick, easy, and flexible

Introduction

One of the most common questions is "how can I print / print preview my Windows Form"? This is quite easily done by getting the form to "draw itself" on the printed page or using the VB Power Packs to do likewise, but this is often unsatisfactory because:

  • the location of components on the form may not be where you want them on the printed page
  • text is drawn at screen resolution
  • every control is drawn (e.g., buttons, the form border, etc.)

The attached component addresses the problem in a different manner.... What you do is drop a FormPrintHelperComponent component onto your form and it extends each control on that form with a set of new properties (look in the Properties window for each control in the section named "MCL Form Print Helper").

Printing helper extended properties

You then set these to indicate:

  • whether or not the control should be printed
  • whether to print it as Text, Image, or Owner Drawn
  • the boundary rectangle to print it in
  • the vertical / horizontal alignment within that area
  • Font and background/foreground colour to use, etc.

The component then allows you to preview the printed page at design time, and to preview or print it at run time.

How It Works

The component implements System.ComponentModel.IExtenderProvider which means it provides properties to the other controls on the form - in the same way as the built-in ToolTip and F1 Help provider components do.

The class is decorated with ProvideProperty attributes which tells the IDE which properties the control provides to extend the properties of the controls on the form. Underlying each of these "properties" are a matched pair of a function and sub routine to get/set the property for the control passed in, which are called if an extended property is changed in the target control's property window.

Extended properties provided by the control

When the component is invoked to print or print preview, it iterates through all the controls on the form that have the extended property Print set to true. It then prints the control according to the other extended properties provided for that control such as boundary rectangle, font, foreground and background colour, etc.

The PrintMode extended property affects how the control is printed. There are three options:

  • PrintAsText - Prints the "Text" property of the control
  • PrintAsImage - Prints the "Image" property of the control if it has one; otherwise, prints the control as a bitmap exactly as it appears on screen
  • PrintAsOwnerDrawn - Passes the control to the OwnerDrawnControlprint event so the application can decide how to print the control

"Print as Image" Printing Functionality

If the control doesn't have an Image attribute, the control is drawn onto a bitmap, which is then printed on the form by using the control class' DrawToBitmap method:

VB
Private Function GetControlImage(ByVal ctlIn As Control) As Image

    Dim Imageproperty As System.Reflection.PropertyInfo
    Imageproperty = ctlIn.GetType.GetProperty("Image", GetType(Image))
    If Imageproperty Is Nothing Then
        Dim imgNew As New Bitmap(ctlIn.Width, ctlIn.Height)
        ctlIn.DrawToBitmap(imgNew, ctlIn.ClientRectangle)
        Return imgNew
    Else
        Return CType(Imageproperty.GetValue(ctlIn, Nothing), Image)
    End If
End Function

"Owner Drawn" Printing Functionality

If you set the extended property PrintMode to PrintAsOwnerDrawn, then at run time, when the print or print preview logic is invoked, an OwnerDrawnControlPrint event will be raised to allow you to programmatically draw the control onto the page canvas.

VB
Private Sub FormPrintHelperComponent1_OwnerDrawnControlPrint(ByVal sender As Object,  _ 
            ByVal e As MCL_Form_Print_Control.OwnerPrintControlEventArgs) _ 
            Handles FormPrintHelperComponent1.OwnerDrawnControlPrint

    '\\ The application code should draw this 
    '\\ control because it is special....
    With e
        If .ControlToPrint.Name = "DateTimePicker1" Then
            e.Canvas.FillRectangle(Brushes.Aqua, e.BoundingRectangle)
            e.Canvas.DrawString(">> " & .ControlToPrint.Text & _
                                "<<",  .ControlToPrint.Font, _
                                Brushes.Azure, e.BoundingRectangle)
        End If
    End With
End Sub

Worked Example

First, compile the attached source code and then add a reference to the control's DLL to your application, and (optionally) add it to the toolbox.

The next step is to layout your Windows form in Design mode with all the controls that you want on it. (You can add controls at a later date, and the extender will pick them up, so don't worry about having the full design in place to start with). You then drag an instance of the component from the tool bar on to your form.

Then, select the control(s) you want to print - e.g., on the form in the demo project in the source code above, the controls Label_Databasename, CheckedListBox_Databases, etc. are to be printed, but the user does not want to print the buttons, Button1 and Button2.

On the control properties pane for the controls to be printed, navigate down to the section "MCL Form Print Utility" and set the extended property named "Print on FormPrintHelperComponent1" to true.

Setting the rich text box mode to PrintAsRichText means the content of a rich text box is printed in what-you-see-is-what-you-get mode.

Selecting Where to Print the Component on the Page

By default, the property "BoundingRectangle on FormPrinthelperComponent1" is set to the same rectangle as the control occupies on the form. You can alter this (to make the layout more suited to the size and orientation of the printed page) by altering the values in this property. To see how this change looks, you can preview the form print layout by selecting the FormPrintHelperComponent instance, and from its smart tag menu, select the option "Preview Document".

Other Extender Provided Properties

The component provides the following extended properties to the form on which it is sited:

  • DocumentName - The name of the document as it will appear in the print queue when printed. This defaults to the name of the form if not set.
  • PaperKind - The paper size to use to print the document (A4, A5, letter, etc.).

The component provides the following extended properties to all the controls on the form on which the component is sited:

  • BackColour - The colour to fill the bounding rectangle of the control before printing it. If this is transparent, then the bounding rectangle will not obscure items printed before it.
  • BoundingRectangle - Where on the page to print the component.
  • ForeColour - The foreground colour to use to print the control (this has no effect if the print mode is not PrintAsText).
  • HorizontalAlignment, VerticalAlignment - How to align the control's text relative to its bounding rectangle for printing.
  • Print - True if it should be printed on the page, false if not.
  • PrintFont - The font to use to print the control's text if the print method is PrintAsText.
  • PrintMethod - How to print the control (see explanation above).
  • TopBorder, BottomBorder, LeftBorder, RightBorder - Pens to use to draw a border around the bounding rectangle on the printed document.

Multi-Page Documents

Of course, there are many cases where a single form needs to be printed over multiple logical pages - for example, if a form has many tabs on it, you might find it sensible to print one logical page per tab.

The component implements this functionality by having a property LogicalPages which is a positive number 1 or greater that is the number of logical pages that this form should be printed over. Then, for each control, two additional extended properties are added that control which pages that control is to be printed on: MultiPageprintMethod which is an enumerated type:

  • PrintOnEveryPage - Print the control on every logical page
  • PrintOnOddPages - Print the control on odd numbered logical pages
  • PrintOnEvenPages - Print the control on even numbered logical pages
  • PrintOnlyOnSpecifiedLogicalPages - Print the control only on the specified pages

If the MultiPageprintMethod is set to PrintOnlyOnSpecifiedLogicalPages, then a second extended property, PrintOnPages (which is a list of boolean values, one for each logical page) is used to set the page(s) to print it on.

Logical Pages?

When the data in a control (such as a multi-line textbox, a rich textbox, or a grid) is too large for the area allocated to print it on the document, you can optionally set it to flow over to a new page until it reaches the end of the data by setting the extended property DataOverflowAction to CreateNewPage.

However, the new page will be the same logical page as the current one (with all the same controls on it), but will be a different physical page. The use of logical pages at the design stage allows a multi part document to be created that does not need to change at run time to accommodate extra data.

Updates

  • Added a UITypeEditor to allow you to set the colour and line width of all the border lines
  • Added an extended property Trimming which controls how words wrap within their bounding rectangle
  • Added an extended property PropertyToPrint to allow you to specify which property of the control you want to print
  • Added a PrinterSettings method that invokes the printer setup dialog box to allow the settings to be changed at run time
  • Added a PageSetup method that invokes a page setup dialog box to allow the user to change the page layout at run time
  • Added multi-page functionality
  • Added code to print a rich text box as rich text (what-you-see-is-what-you-get) by setting RTFPrintMethod
  • Added C# version of the component

License

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