Silverlight 4 vs Flex 4: Printing

I’ve wanted to do a “Silverlight vs Flex” series for quite a while now. Both Silverlight and Flex will reach version 4 during the first quarter of this year, at least, that’s what the roadmaps say. With both reaching version 4, this seems like the perfect time to do a comparison about how to implement certain features. Silverlight has been catching up with Flex, but in Silverlight 4, there are features in Silverlight that are just not possible in Flex (COM interop / Drag and Drop from the desktop), while other features that previously were only possible in Flex, are now also available in Silverlight 4. Whether the implementation of these features in Silverlight is as mature as in Flex is what we are going to find out in this series. We’re going to start with how printing is implemented on both platforms.
Printing in Silverlight 4
Central to printing in Silverlight 4 is the PrintDocument class. Printing in Silverlight always has the same steps:
- Create a PrintDocument object.
- Set the document name on the PrintDocument object.
- Attach eventhandlers for the PrintPage event and optionally for the StartPrint and EndPrint events.
- In the eventhandler for the PrintPage event, create the visual you want to print and assign it to the RootVisual property of the incoming PrintPageEventArgs object.
- Specify whether another page will be printed by assigning the HasMorePages property of the incoming PrintPageEventArgs object true or false.
- Repeat step 4 and 5 as long as there are pages to print.
All of these steps are shown in the code behind of a Silverlight application that prints “Hello World” when a button is pressed:
1: using System;
2: using System.Windows;
3: using System.Windows.Controls;
4: using System.Windows.Printing;
5:
6: namespace HelloPrinter
7: {
8: public partial class MainPage : UserControl
9: {
10: public MainPage()
11: {
12: InitializeComponent();
13: }
14:
15: private void button1_Click(object sender, RoutedEventArgs e)
16: {
17: PrintDocument printDoc = new PrintDocument();
18: printDoc.DocumentName = "Hello World from Silverlight";
19: printDoc.PrintPage += new EventHandler<PrintPageEventArgs>(printDoc_PrintPage);
20: printDoc.Print();
21: }
22:
23: void printDoc_PrintPage(object sender, PrintPageEventArgs e)
24: {
25: StackPanel panel = new StackPanel() { Orientation = Orientation.Horizontal };
26: panel.Children.Add(new TextBlock() { Text = "Hello ", FontFamily = new System.Windows.Media.FontFamily("Arial"), FontSize = 12 });
27: panel.Children.Add(new TextBlock() { Text = "World", FontFamily = new System.Windows.Media.FontFamily("Arial"), FontSize = 12 });
28: e.PageVisual = panel;
29: e.HasMorePages = false;
30: }
31: }
32: }
Line 15 is the eventhandler that gets called when the button is pressed. What stands out is the fact that the visual you want to print, doesn’t have to be part of the visual tree that Silverlight renders to the screen. Another thing to consider is that Silverlight automatically stretches the RootVisual to the height and width of the page. You can check this size by reading the PrintableArea property of the incoming PrintPageEventArgs object. You can override this behavior by setting the height and width properties of the RootVisual explicitly.
Printing in Flex 4
Printing has been in Flex since the first version. Just like in Silverlight it has a couple of steps to follow, but the programming model is quite different. Printing in Flex is not event driven, this are the steps to take in Flex:
- Create a FlexPrintJob object, you can compare this more or less with Silverlight’s PrintDocument class.
- Specify with a boolean whether you want to print in vector graphics or in bitmap graphics. Bitmap supports transparency, vector not but prints in higher quality.
- Call the FlexPrintJob’s start() method. This will show the print dialog and returns true if the user clicked ok. If the start() method returned true, the printer is now waiting for us to send it some pages.
- Create a visual object you like to print.
- Add the visual object to the display list.
- Add the object to the job using FlexPrintJob’s addObject() method. Every visual object is another page, except when a visual object is larger than one page, Flex automatically detects this and prints the object on multiple pages.
- When you’re done adding pages / visual objects, call the send() method of the FlexPrintJob class.
- Remove the visual objects you added to the display list just for printing.
All of these steps are shown in the code behind of a Flex application that prints “Hello World” when a button is pressed:
1: protected function button1_clickHandler(event:MouseEvent):void
2: {
3: var job : FlexPrintJob = new FlexPrintJob();
4: job.printAsBitmap = false;
5: if(job.start()) {
6: var group : HGroup = new HGroup();
7: group.height = job.pageHeight;
8: group.width = job.pageWidth;
9: var text : SimpleText = new SimpleText();
10: text.text = "Hello ";
11: text.setStyle("fontFamily", "Arial");
12: text.setStyle("fontSize",12);
13: group.addElement(text);
14: text = new SimpleText();
15: text.setStyle("fontFamily", "Arial");
16: text.setStyle("fontSize",12);
17: text.text = "World";
18: group.addElement(text);
19:
20: addElement(group);
21:
22: job.addObject(group, FlexPrintJobScaleType.NONE);
23:
24: job.send();
25: removeElement(group);
26: }
If you look at the code and my explanation above it you can see that Flex printing requires more steps. This is because of the following differences:
- In Flex , you can specify how to print, in bitmap mode or in vector mode.
- Flex doesn’t automatically scale the visual object to the page size. You can supply a constant defined in the FlexPrintJobScaleType class to specify how Flex should scale when you call the addObject() method, but “NONE” was the only option that printed anything. To scale the object to the page size I set the width and height of the HGroup to print to the “pageHeight” and “pageWidth” properties of the FlexPrintJob class.
- Components in Flex are only printed if they are part of the display list. Don’t worry, in the example above you don’t see the HGroup popping up and disappearing during the print. If you remove the visual object from the display list after printing, nobody will notice.
Conclusion
I think the printing in Flex is somewhat more mature than the printing in Silverlight, I like the option of the higher quality vector printing in Flex and that Flex automatically spreads large visual objects across multiple pages, instead of just cutting them off, like Silverlight does. Also, in Flex there is more support for printing than shown above, for example a lot of components have a prepareToPrint() method, which they can override to make themselves look better when printed, for example, by removing scrollbars (they have no use on paper :)), you can also customize how components print themselves by subclassing the component and overriding this method. Finally, there are components especially designed for printing, a PrintDataGrid for example, which makes sure that only whole rows are printed on each page. What I do like in Silverlight is the whole programming model, it feels more intuitive to me. Just for comparison, below are images showing the quality of the prints when printed to a .XPS file. The Flex printing with Vector graphics clearly has the best quality.
Flex printing:![]() |
Silverlight printing:![]() |
Flex Vector printing:![]() |