Twitter Facebook RSS Feed

martes, 01 de diciembre de 2009 a las 00:37hs por Gustavo Cantero (The Wolf)

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.

Dialogo impresión
Para probar la impresión yo lo envié a la impresora virtual llamada “Microsoft XPS Document Writer”, para que me cree un archivo XPS y poder verlo luego desde mi navegador:

Impresión XPS
Bien, como ejemplo sirve, pero cómo hacemos para imprimir otra cosa que no sea la aplicación o para imprimir varias páginas? Eso lo voy a explicar a continuació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.

7 comentarios »

  1. Sam dice:

    Consulta, como sale impreso el documento? es como lo hace javascript con el encabezado del navegador? gracias muy buen contenido

  2. Juan Aragón dice:

    Si no quiero que se presente el cuadro de dialogo a la hora de imprimir, es decir, mandar la impresión y que tome mi impresora por defecto sin necesidad de escogerla en el cuadro de dialogo, ¿Cómo se haría?

  3. Fher dice:

    Disculpa, este método es posible usarlo para imprimir en una impresora de Tickets? De no ser asi, que me recomiendas?

    Saludos

    • Depende de la impresora, si está instalada en el sistema operativo como una impresora normal no deberías tener ningún problema, pero si va conectada al puerto serie (RS232) o es una impresora fiscal no vas a poder hacerlo desde Silverlight.
      Suerte!

  4. jaime arias dice:

    Hola. Enhorabuena por este sitio.
    Me parece muy interesante todo lo que estoy viendo.

    Saliendo del hilo, y con antelación pido disculpa por ello, sabes si ¿se puede acceder desde una aplicación con Silverlight a recursos locales como un lector de tarjetas mifare, y poder leer la tarjeta?, tienes alguna idea de como poder hacerlo.

    Gracias de antemano.

    Un saludo

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.