Una de las características más votadas en el sitio Microsoft® Connect por los desarrolladores que utilizamos Silverlight es la posibilidad de imprimir. Esto ahora es posible utilizando Silverlight 4 beta y la nueva clase PrintDocument del espacio de nombres System.Windows.Printing.
Primero vamos a hacer una introducción rápida sobre como imprimir desde Silverlight. La clase PrintDocument básicamente envía a la impresora el contenido de cualquier objeto UIElement, el cual debe ser establecido a través de uno de los parámetros del evento PrintPage que se dispara luego de llamar al método Print. Nótese que al tratarse de objetos UIElement se puede imprimir cualquier elemento gráfico que estemos utilizando en nuestras aplicaciones, por ejemplo, Image, TextBlock o incluso grillas complejas con elementos variados o con más grillas en su interior.
Supongamos que queremos imprimir, desde un botón puesto en el XAML, la pantalla de la aplicación (sería algo así como una captura de la aplicación), para esto podríamos poner el siguiente código en el XAML:
<UserControl x:Class="Print.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> <StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center"> <TextBlock Text="Texto de prueba" Margin="10" FontSize="30"> <TextBlock.Effect> <DropShadowEffect /> </TextBlock.Effect> </TextBlock> <Button Content="Imprimir" Click="Button_Click" /> </StackPanel> </UserControl>
Y este otro en el código:
using System.Windows; using System.Windows.Controls; using System.Windows.Printing; namespace Print { public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } private void Button_Click(object sender, RoutedEventArgs e) { PrintDocument objDoc = new PrintDocument(); objDoc.PrintPage += (s, args) => { args.PageVisual = this; }; objDoc.Print(); } } }
En el código de C# podemos ver tres pasos sencillos realizados para imprimir la página Silverlight completa: creamos el objeto PrintDocument, creamos un delegado anónimo para el evento PrintDocument que establezca la propiedad PageVisual (aquí es donde hay que establecer el elemento a imprimir) y por último llamamos al método Print. Al llamar a este método el sistema operativo nos muestra el diálogo de impresión.
La clase PrintDocument en realidad posee tres eventos: StartPrint, PrintDocument y EndPrint, los cuales se ejecutan antes, durante y después de realizar la impresión respectivamente.
El primer evento, StartPrint, se dispara luego de llamar al método Print y de que el usuario cliqueado “Imprimir” en el diálogo de impresión. Este evento es utilizado para configurar lo necesario antes de la impresión, por ejemplo, acomodar controles, ocultar elementos, etc.
El siguiente evento a ejecutar es PrintDocument, al cual se le pasa como parámetro un objeto del tipo PrintPageEventArgs. Este objeto posee tres propiedades interesantes:
- PageVisual: en esta propiedad debemos establecer el objeto del tipo UIElement que queremos que se imprima en la página actual, por ejemplo, una grilla con información, una imagen, etc. Este elemento a imprimir no necesariamente debe estar en el XAML, podemos crearlo programáticamente y enviarlo luego a imprimir.
- PrintableArea: aquí nos pasa el tamaño del área imprimible que disponemos. Cabe mencionar que este valor variará dependiendo de la impresora seleccionada por el usuario y del tamaño del papel elegido.
- HasMorePages: en esta propiedad podemos establecer si luego de la página que estamos enviando a imprimir hay más páginas. En caso de que establezcamos como true el valor de esta propiedad, luego de finalizado el delegado actual, se disparará nuevamente el evento PrintDocument para imprimir las siguientes páginas.
Por último nos queda el evento EndPrint, donde podemos realizar cualquier acción que necesitemos hacer luego de finalizada (o enviada al spooler) la impresión. Este evento recibe, como uno de sus parámetros, un objeto del tipo EndPrintEventArgs, el cual tiene una propiedad llamada Error que es donde el Framework nos devuelve cualquier excepción generada al momento de la impresión. Si en el ejemplo anterior ante un error quisiéramos mostrarle al usuario el mensaje de la excepción, deberíamos modificar el código del evento Click del botón por el siguiente:
PrintDocument objDoc = new PrintDocument(); objDoc.PrintPage += (s, args) => { args.PageVisual = this; }; objDoc.EndPrint += (s, args) => { if (args.Error != null) MessageBox.Show(args.Error.Message, "ERROR", MessageBoxButton.OK); }; objDoc.Print();
Regresando a la clase PrintDocument, ésta posee también (además del método Print que ya vimos) una propiedad llamada DocumentName, donde podemos establecer el nombre de nuestro documento, el cual se verá en la cola de la impresora.
Por último les dejo el proyecto de ejemplo realizado con Visual Studio® 2010 beta 2.