ARTICLE

Exploring Printing in Silverlight 4.0

Posted by Mike Gold Articles | Silverlight with C# June 04, 2010
Let’s look at the extremely useful feature of printing in the newest version of silverlight.
Reader Level:
 

Introduction

A pointedly absent feature in Silverlight 1 through 3 was the ability to print.  What was the use of writing silverlight applications
if you couldn't use them to access the peripherals on your machine?  Well now you can.  Let's begin to look at this extremely
useful feature in the newest version of silverlight.

Installation Note

In order to use Silverlight 4.0 in Visual Studio 2010, make sure you download Silverlight Tools for Visual Studio.

Creating your App

Let's start by creating a new silverlight application in 2010.  Open a new project from the file menu and give your
silverlight application a relevant name.

1.gif
 
Figure 1 - Creating the Silverlight Application to Demonstrate Printing

Double click on MainPage.xaml and start constructing the item you want to print using Silverlight components. 
In my example, I've constructed a simple business card with logo and contact info just to give you an idea of how
to print a basic XAML form.

2.gif
 
Figure 2 - The Application Design

We'll also add a button to the design to trigger the printing, but we'll place the button outside the visual tree
we wish to print. After quickly throwing together a sample from a myriad of Images and labels and running
the program, here is what we get:

3.gif
 
Figure 3 - The Silverlight Business Card Application Running in the Browser

Now let's see how we can print out our work of art to a physical piece of paper.

It's all about the PrintDocument...Again

You may remember the PrintDocument when you were developing printing in Windows Forms.  Things haven't changed
in the name of the class, but they have changed slightly in the approach Microsoft is taking when printing Silverlight apps. 
The PrintDocument operates on the visual tree instead of a graphics object. It still has the PrintPage event, but instead
of drawing GDI+ commands to the printer (as in Windows Forms),  you draw the Visual Tree.  Actually you don't really
draw the visual tree persay. All you do is assign the part of the Visual Tree you want to print to  the PrintPageEventArgs
PageVisual property inside the PrintPage event handler.

Most of the print functionality is self contained in the PrintDocument as it was in Windows Forms, so let us take a closer look
at the properties and methods of the PrintDocument class.

Propery or Method Description
PrintDocument() Constructs a print document
PrintedPageCount Number of Pages Printed
Print Starts the printing process by bringing up the print dialog.
BeginPrint event Occurs after the Print method has been called and the print dialog has closed, but before the PrintPage handling occurs
PrintPage event Occurs during the printing of each page
EndPrint event Occurs after printing is completed or cancelled

Table 1 - PrintDocument Members in Silverlight

As you can see, there is not much to the PrintDocument class.  Some of the functionality for printing is divided among the event
arguements inside each event handler.  The Print method kicks off printing and the BeginPrint, PrintPage, and EndPrint events allow
us to create event handlers to intercept printing before, during, and after the printing process respectively.  For example, BeginPrint
can be used to put up an active window with a cancel button.  EndPrint can be used to take the active window down.  PrintPage is
where we do all the hard work of assigning the visual tree.  

The PrintPage event handler takes a PrintPageEventArgs argument in which we can use to manipulate printing.  Only two of the
properties are settable: HasMorePages and PageVisual,  all of the rest of the properties are feedback from the framework. 
We can use HasMorePages to indicate there is more of the Visual Tree to print that won't fit on the current page by setting it
to true in the PrintPage event handler.  Or we can use HasMorePages to put different parts of the Visual Tree on different pages.  

MemberDescriptionTypeDefault
HasMorePagesSet or get if the printer needs to print additional pagesboolfalse
PageMarginsThe margins of the page being printedThickness
PageVisualThe Visual Tree Element to PrintUIElementnull
PrintableAreaSize of the Printable Area in PixelsSize0.0, 0.0

Table 2 - PrintPageEventArgs Members

The Code

The code for printing the business card is fairly straightforward.  In the example, we call the Print method on the PrintDocument
object to cause printing to happen from Silverlight.  This triggers the 3 events we have mentioned BeginPrint, PrintPage, and EndPrint. 
We don't do anything in BeginPrint in this sample to keep it simple.  Inside of PrintPage, we assign the part of our Visual Tree that we
wish to send to the printer.  In the example, the business card lies inside a border, so we send the Border control to the printer. 
Below is the XAML for the border called AreaToPrint.

<Border x:Name="AreaToPrint" BorderThickness="1" Background="Beige" BorderBrush="Black">

The Border and everything inside it will be printed when it is assigned to the PageVisual property of the PrintPageEventArgs. 
The EndPrint event handler just checks to see if anything went wrong during printing, and if something went wrong, it alerts
the user to the problem.

Listing 1 - Printing the Business Card in Silverlight Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Printing;

namespace UsingPrintingInSilverlight
{
    public partial class MainPage : UserControl
    {
        // construct the print document for printing
        PrintDocument printDocument = new PrintDocument();
        public MainPage()
        {
            InitializeComponent();
            // wire up all the events needed for printing
            printDocument.BeginPrint += new EventHandler<BeginPrintEventArgs>(printDocument_BeginPrint);
            printDocument.PrintPage += new EventHandler<PrintPageEventArgs>(printDocument_PrintPage);
            printDocument.EndPrint += new EventHandler<EndPrintEventArgs>(printDocument_EndPrint);
        }
        void printDocument_EndPrint(object sender, EndPrintEventArgs e)
        {
            // if an error occurred, alert the user to the error
            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message);
            }
        }
        void printDocument_PrintPage(object sender, PrintPageEventArgs e)
        {
            // assign the visual tree we want to print to the event arg's PageVisual property
            e.PageVisual = AreaToPrint;
        }
        void printDocument_BeginPrint(object sender, BeginPrintEventArgs e)
        {
            // we don't do anything special here
        }
        private void PrintButton_Click(object sender, RoutedEventArgs e)
        {
            // when the button is pressed, print the business card
            printDocument.Print("My Business Card");
        }
    }
}

Running the Code

If we compile and run our application and press the button, the Print Dialog comes up.  I chose the preview option
that came with my printer to demonstrate printing without having to waste paper (The printer prints the equivalent document). 
As you can see, Silverlight has successfully called the printer from within the browser and allowed me to print my business card.

4.gif 

Figure 4 - Print Dialog Preview Called from Silverlight Application

Conclusion

Printing is one of the most awaited features in Silverlight and it is finally here in Silverlight 4.0.  Its feature set
seems to be a little more limited than say Windows Forms, but it's good enough for most applications from
the browser and opens up a host of opportunities for writing rich printing applications on the web. 
Anyway,  if you have an inkling for some cool apps in Silverlight, don't hold back.  Take advantage of the new features in
Silverlight and Visual Studio 2010 to test your creative ideas.

COMMENT USING