Featured Posts

Anunciando: Taller de Silverlight 4Anunciando: Taller de Silverlight 4 Antes que otra cosa, quiero agradecer a todos y todas quienes me ayudaron a contestar la encuesta que preparé en días pasados.  Recibí más de 250 respuestas de personas...

Readmore

Silverlight Tour–Guadalajara (08 al 10 de Septiembre... El interés y difusión de Silverlight como plataforma de desarrollo está siendo cada vez más grande y muchas empresas están optando por esta tecnología para construir...

Readmore

Curso gratuito de Introducción a Silverlight 4 – 2da. ParteCurso gratuito de Introducción a Silverlight... Tengo el gusto de informarles que ya está disponible la segunda parte del Curso gratuito de Introducción a Silverlight 4 en Español, el cual ahora consta de un total...

Readmore

Silverlight Tour en Español – Ahora con controles de Telerik!Silverlight Tour en Español – Ahora con... Tengo el gusto de informar que tal como sucede con el Silverlight Tour en USA y Canadá, ahora también el Silverlight Tour en Español en asociación con Telerik incluye...

Readmore

Rodrigo Díaz Concha Rss

Silverlight 4 Beta – Impresión, Modularización y Parámetros

Posted on : 23-11-2009 | By : Rodrigo | In : Silverlight 4

Tags: , ,

0

En el artículo anterior vimos cómo mandar a imprimir múltiples páginas dentro de nuestras aplicaciones de Silverlight 4.  En este artículo iremos un paso más allá, modularizando un poco más nuestro código e implementando la funcionalidad de parametrización de las opciones de impresión (encabezado y márgen principalmente).  Esto nos ofrecerá un código más robusto que permita escenarios de impresión más detallados.  Nota: esta implementación es una propuesta e idea para poder modularizar y de ninguna manera pretende ser el único mecanismo o camino para lograrlo.

La Solución

Utilizaremos la misma solución del proyecto del artículo anterior.  A esta solución le agregaremos un nuevo proyecto de tipo Silverlight Class Library para poder incorporar en él la funcionalidad de impresión, en vez de tenerlo directamente en el code-behind de MainPage.xaml del proyecto Silverlight.  Al nuevo proyecto le pondremos el nombre de SL4.Demo.Impresion.Util y agregaremos dos clases: Impresion.cs y Parametros.cs

image

image

Impresion.cs

Será en esta clase en donde implementaremos el código de impresión.  Esta clase tendrá un método público Imprimir() el cual nos servirá como manejador del evento clic del botón en donde deseemos invocar la funcionalidad (botón button2 en MainPage.xaml).  De esta manera estaremos manejando el evento clic en una instancia de Impresion en vez de hacerlo directamente en code-behind.

La clase Impresion será de tipo genérica, ya que necesitamos conocer de antemano el tipo de contenido que se mandará a imprimir para poder realizar el filtrado de los registros de manera adecuada.  En nuestro ejemplo es un objeto de tipo Albumes.

Por las razones descritas, el código de MainPage.xaml.cs quedará de la siguiente manera:

public partial class MainPage : UserControl
    {
        SL4.Impresion.Impresion<Album> util = null;

        public MainPage()
        {
            InitializeComponent();

            util = new Impresion.Impresion<Album>(this.Resources["albumes"] as Albumes,
                this.Resources["ImpresionDataTemplate"] as DataTemplate,
                40.0,
                "Documento de Prueba",
                "Lista de Álbumes – The Beatles");

            util.ImpresionFinalizada += new EventHandler(util_ImpresionFinalizada);
            this.button1.Click += new RoutedEventHandler(button1_Click);
            this.button2.Click += util.Imprimir;
        }

        void button1_Click(object sender, RoutedEventArgs e)
        {
            util.Configurar();
        }

        void util_ImpresionFinalizada(object sender, EventArgs e)
        {
            MessageBox.Show("ok!!!");
        }

    }

En el constructor de la clase Impresion mandamos los parámetros necesarios los cuales son la fuente de datos, el DataTemplate que será usado para definir la distribución de los elementos, el alto que tendrá cada línea (corresponde al alto del registro que tiene el Grid del DataTemplate), el nombre que deseamos que aparezca en el panel de la impresora y el título deseado.

Además, con la siguiente línea:

this.button2.Click += util.Imprimir;

Estamos definiendo como manejador del evento Click del botón al método público Imprimir implementado en la clase Impresion.  Será en ese método en donde implementaremos la funcionalidad para mandar a imprimir nuestro contenido.

También cabe resaltar:

util.ImpresionFinalizada += new EventHandler(util_ImpresionFinalizada);

Con la línea anterior estamos manejando el evento ImpresionFinalizada, evento que ha sido implementado también en la clase Impresion y que se disparará una vez finalizado el proceso de impresión (efectivamente, en el evento EndPrint del objeto PrintDocument).  Lo interesante de este mecanismo es que si no establecemos un manejador para el evento, la clase impresión tiene el suyo propio: muestra un MessageBox cuando se está ejecutando adentro del navegador o muestra una ventana de Notificación (característica nueva en Silverlight 4) indicando que la impresión ha concluído.  El siguiente fragmento de código muestra este concepto:

….
            pd.EndPrint += (s, a) =>
            {
                this.paginaActual = 0;

                if (a.Error != null)
                    throw a.Error;
                if (ImpresionFinalizada != null)
                {
                    ImpresionFinalizada(this, null);
                }
                else
                {
                    Notificar();
                }
            };
            pd.Print();
        }

        void Notificar()
        {
            if (Application.Current.IsRunningOutOfBrowser)
            {
                NotificationWindow nw = new NotificationWindow();
                nw.Content = new TextBlock() { Text = "Impresión finalizada" };
                nw.Show(1000);
            }
            else
            {
                MessageBox.Show("Impresión finalizada");
            }
        }

 

Si ejecutamos la aplicación Fuera del Navegador, la notificación sería mostrada (quitando el manejador de evento personalizado de nuestro código):

image

Parametros.cs

 

La clase Parametros nos servirá para permitir al usuario que modifique los parámetros para la impresión, principalmente para el encabezado y el márgen izquierdo para el ItemsControl.  El mecanismo seleccionado para este efecto será tener un ChildWindow (llamado Configuracion) el cual contenga un control de tipo DataForm; para permitir la edición de los valores se una manera sencilla y rápida.  La siguiente figura muestra la caja de diálogo de configuración en acción:

image

Esto brinda al usuario una manera de poder cambiar algunos parámetros a la hora de imprimir.  El resultado será el siguiente (impresión a un archivo .xps):

image

Pueden descargar el código de aquí

Pueden ver el demo en vivo aquí (requiere Silverlight 4)

  • Share/Bookmark

Silverlight 4 Beta – Impresión de Múltiples Páginas

Posted on : 21-11-2009 | By : Rodrigo | In : Silverlight 4

Tags: , ,

5

En el artículo anterior, vimos los fundamentos del modelo de clases para imprimir desde nuestras aplicaciones de Silverlight 4.  Recordemos que la propiedad HasMorePages indica si nuestro documento tiene más páginas que imprimir; si HasMorePages es true entonces el evento PrintPage se disparará nuevamente hasta que HasMorePages sea false.

En este artículo veremos cómo aprovechar esta característica para poder mandar a imprimir un catálogo de artículos (en este ejemplo, un catálogo de álbumes de música) ya que este escenario será bastante común en las Aplicaciones de Línea de Negocio que construyamos con Silverlight 4.

Escenario

Dado el siguiente escenario:

1

Podemos apreciar que tenemos un ListBox el cual contiene una lista de álbumes de música.  Además estamos cambiando el DataTemplate para poder mostrar de una mejor manera cada uno de esos elementos.  El siguiente fragmento de código muestra el Xaml de la aplicación:

<UserControl x:Class="Demo.SL4.ImpresionMultiple.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"
xmlns:local="clr-namespace:Demo.SL4.ImpresionMultiple"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="500">
    <UserControl.Resources>
        <local:Albumes x:Key="albumes" />
        
        <DataTemplate x:Key="VistaDataTemplate">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="100" />
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>
                <Border BorderBrush="Black" Padding="3" BorderThickness="2" CornerRadius="10">
                   <Image Source="{Binding Foto}"
                       Width="100" />
                    </Border>
                <StackPanel Grid.Column="1">
                    <TextBlock Text="{Binding Titulo}"
                           FontSize="20" />
                <TextBlock Text="{Binding Banda}" />
                     </StackPanel>
                   </Grid>
        </DataTemplate>
    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" Background="White" DataContext="{StaticResource albumes}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <ListBox Grid.Column="1"
                 HorizontalAlignment="Left"
                 Margin="5"
                 Name="listBox1"
                 VerticalAlignment="Top"
                 Width="450"
                 Height="450"
                 ItemsSource="{Binding}"
                 ItemTemplate="{StaticResource VistaDataTemplate}" />
        <StackPanel Height="228"
                    HorizontalAlignment="Left"
                    Name="stackPanel1"
                    VerticalAlignment="Top"
                    Margin="5">
            <Button Height="50"
                    Name="button1"
                    Width="120">
                <Button.Content>
                    <StackPanel>
                        <TextBlock HorizontalAlignment="Center">Imprimir</TextBlock>
                        <TextBlock HorizontalAlignment="Center">ListBox</TextBlock>
                    </StackPanel>
                </Button.Content>
            </Button>
            <Button Height="50"
                    Name="button2"
                    Width="120">
                <Button.Content>
                    <StackPanel>
                        <TextBlock HorizontalAlignment="Center">Impresión</TextBlock>
                        <TextBlock HorizontalAlignment="Center">Personalizada</TextBlock>
                    </StackPanel>
                </Button.Content>
            </Button>
        </StackPanel>
    </Grid>
</UserControl>

 

Impresión de Elementos

La propiedad PageVisual del objeto de argumentos en el evento PrintPage indica ultimadamente cuál es el contenido a imprimir, siendo este contenido parte del árbol de Xaml o no.  Es decir que, si establecemos el ListBox como el PageVisual…

pd.PrintPage += (s, a) =>
            {
                //Establecemos el ListBox como el PageVisual
                a.PageVisual = listBox1;
            };

…nuestro resultado de impresión será el siguiente (impresión en XPS):

2

Tal vez este mecanismo no sea el adecuado para presentar correctamente la impresión, ya que se imprime el elemento tal y como aparece en pantalla; es decir, una “fotografía” del elemento (incluyendo las barras de scroll, los bordes, etc.).

Impresión Personalizada

Podemos lograr un grado más alto de personalización creando de manera dinámica el contenido Xaml que deseamos imprimir.  En el caso de este ejemplo generaremos dinámicamente un Canvas que contenga un encabezado, además de un ItemsControl que despliegue todos y cada uno de los elementos a imprimir. Además de lo anterior, nos aseguraremos que la impresión permita múltiples páginas y que se impriman los registros en cada página de manera correcta.

Canvas

Tal como en el artículo anterior, creamos un Canvas que tenga el mismo tamaño del área de impresión disponible, según la impresora seleccionada:

pd.PrintPage += (s, a) =>
{
    canvas = new Canvas() { Width = a.PrintableArea.Width, Height = a.PrintableArea.Height };
    …

Encabezado

Para cada página a imprimir, se agregará un encabezado que contenga un logo a la izquierda, el título del encabezado centrado, y un texto que indique el número de página actual.

Nota: Hay un issue con Silverlight 4 Beta que impide la impresión de imágenes creadas dinámicamente.

Lista de Elementos

Esta es la parte más importante de este escenario.  Necesitamos soportar el hecho de que habrá más de una página al momento de imprimir.  En el ejemplo de este artículo tenemos un objeto llamado Albumes (List<Album>) el cual tiene un total de 42 álbumes.

Para la impresión personalizada crearemos otro DataTemplate llamado ImpresionDataTemplate el cual desplegará de manera diferente los mismos elementos de la pantalla.  Por ejemplo, quitaremos la imagen de cada álbum, además desplegaremos los elementos dentro de un Grid con cuatro columnas.  Las columnas que mostraremos serán Titulo, Banda, Inventario y FechaLanzamiento.  El siguiente fragmento de Xaml muestra el DataTemplate para la impresión:

<DataTemplate x:Key="ImpresionDataTemplate">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="150" />
                    <ColumnDefinition Width="120"/>
                    <ColumnDefinition Width="100" />
                    <ColumnDefinition Width="100" />
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="40" />
                </Grid.RowDefinitions>
                    <TextBlock Text="{Binding Titulo}" FontWeight="Bold" Grid.Column="0" />
                    <TextBlock Text="{Binding Banda}" Grid.Column="1" />
                    <TextBlock Text="{Binding Inventario}" Grid.Column="2" />
                <TextBlock Text="{Binding FechaLanzamiento}"
                           Grid.Column="3" />
            </Grid>
        </DataTemplate>

En el método de creación del listado por página (método CrearLista()) crearemos un ItemsControl el cual su DataTemplate sea el descrito arriba.  Asimismo, estableceremos como su fuente de datos (propiedad ItemsSource) únicamente los registros que quepan en la página actual.  Con los métodos de extensión Skip() y Take() podemos fácilmente leer cierto número de registros del objeto Albumes según la página actual.  El siguiente fragmento de código muestra este concepto:

void CrearLista(int pagina)
        {
            ItemsControl lista = new ItemsControl();
            lista.Width = canvas.Width;
            lista.ItemTemplate = this.Resources["ImpresionDataTemplate"] as DataTemplate;

            //Obtiene únicamente los registros que van en la página actual
            //identificada en el argumento 'pagina' del método
            lista.ItemsSource = fuenteDatos.Skip((int)(pagina*lineasPorPagina)).Take((int)lineasPorPagina);
            
            //Agregamos la lista al Canvas
            canvas.Children.Add(lista);

            //Respetamos el alto del encabezado
            Canvas.SetTop(lista, altoEncabezado);

            //Incrementamos el contador
            paginaActual++;
        }

Finalmente, en el evento PrintPage invocamos los métodos de creación del encabezado y el de la creación de elementos por página:


CrearEncabezado("Lista de Álbumes");

CrearLista(paginaActual);

a.PageVisual = canvas;

a.HasMorePages = !(paginaActual == totalPaginas);

Muy importante en el código anterior es el valor de la propiedad HasMorePages.  En este ejemplo estamos indicando si hay más páginas siempre y cuando el contador (variable paginaActual) sea diferente al número total de páginas (variable totalPaginas).  Recordemos que si HasMorePages es true, el evento PrintPage nuevamente se disparará, provocando así la impresión de todas y cada una de las páginas del listado.

El resultado:

Impresión de dos páginas en Silverlight 4 Beta

Cabe mencionar que el DataTemplate específico para la impresión no es el único mecanismo para hacerlo de manera personalizada, también pudimos haber hecho un StackPanel o Grid de manera dinámica y leer programáticamente (un foreach tal vez) cada Album de Albumes programáticamente e ir agregando al contenedor los elementos manualmente.

Resumen

A través de la propiedad HasMorePages tenemos el control para indicar si nuestro documento a imprimir tiene múltiples páginas.  Asimismo vimos que un DataTemplate específico para la impresión es un mecanismo que nos facilita la manera en la que queremos que se imprima una lista de elementos en un reporte.

Pueden descargar el código fuente aquí

Pueden ver el demo en vivo aquí (requieres Silverlight 4 Beta instalado)

  • Share/Bookmark

Silverlight 4 Beta – Impresión

Posted on : 21-11-2009 | By : Rodrigo | In : Silverlight 4

Tags: , ,

5

Una de las características más esperadas y solicitadas por la comunidad de Silverlight es el soporte de impresión dentro de las aplicaciones, esto es, la capacidad de poder mandar a imprimir el contenido que estemos viendo en la aplicación ya sea una lista de datos de un DataGrid o ListBox o simplemente tomarle una “foto” a la pantalla y enviarla a papel o alguna de las impresoras virtuales instaladas en nuestros equipos (por ejemplo: OneNote, XPS, PDF, etc.).  Silverlight 4 Beta incluye esta característica a través de un modelo de clases muy sencillo.  De hecho este modelo me recuerda al modelo de impresión que tenemos en las aplicaciones Windows Forms desde hace ya mucho tiempo.

Clase System.Windows.Printing.PrintDocument

Las clases para el soporte de impresión dentro de Silverlight han sido incorporadas al espacio de nombres System.Windows.Printing, el cual contiene entre otras cosas la clase PrintDocument.  Esta clase PrintDocument es la clase responsable de mandar a imprimir el contenido que deseemos.

La clase PrintDocument no expone alguna propiedad para que podamos determinar el contenido que deseemos imprimir.  No obstante, el método Print() al ser ejecutado abre la caja de diálogo de impresión de nuestro sistema operativo.

1

Una vez seleccionada la impresora destino (física o virtual), disparará la siguiente secuencia de eventos:

  1. StartPrint
  2. PrintPage
  3. EndPrint

Evento StartPrint

El evento StartPrint se dispara una vez cerrada la caja de diálogo de selección de impresora.  Inmediatamente después se dispara el siguiente evento: PrintPage.

Evento PrintPage

Seguido del evento StartPrint se disparará el evento PrintPage.  Este es el evento más importante en el modelo de impresión ya que es en los argumentos donde debemos establecer efectivamente el contenido que deseamos imprimir.  Esto es definido en la propiedad PageVisual que es de tipo UIElement.  Ya que es de tipo UIElement podemos establecer como contenido en realidad cualquier cosa: ya sea que esté presente en el árbol de Xaml o que sea contenido creado de manera dinámica (a través de código o usando XamlReader.Load(), etc.).  Por ejemplo, si deseamos tomar una “fotografía” a la aplicación actual e imprimirla, podemos establecer como PageVisual el objeto contenedor raíz (ej. LayoutRoot).  O de lo contrario, si queremos crear una impresión personalizada podemos generar contenedores y elementos de manera dinámica tal y como lo muestra este artículo.

Además de la propiedad PageVisual contamos con un par de propiedades: HasMorePages y PrintableArea.

HasMorePages es una propiedad que indica si todavía hay más páginas que imprimir, por ejemplo en el caso de documentos largos, listas, catálogos etc.  Si establecemos esta propiedad a true, entonces el evento PrintPage volverá a dispararse.

PrintableArea indica el tamaño que tiene el área de impresión según la impresora seleccionada.  Por ejemplo no es el mismo tamaño si mandamos a imprimir a OneNote que a un PDF o a una impresora física.  Esta propiedad es de tipo Size y nos servirá también para calcular márgenes, posiciones de elementos, etc.

Cabe mencionar que, si la impresora seleccionada requiere todavía de la interacción del usuario, esta continuará (para indicar el nombre de un archivo .xps o .pdf por ejemplo).

Evento EndPrint

El evento EndPrint se disparará una vez terminado el proceso de impresión.

Ejemplo

Comencemos con crear un nuevo proyecto de Silverlight 4 a través de Visual Studio 2010 (Beta 2 es la versión más reciente en el momento de escribir este artículo).  A este proyecto le pondremos de nombre Demo.SL4.Impresion.  Visual Studio creará la solución junto con el proyecto adecuado tal y como lo esperamos.

Agregaremos a nuestro MainPage.xaml el siguiente código:

<Grid x:Name="LayoutRoot" Background="White">
        <Button Content="Una página"
                Height="47"
                HorizontalAlignment="Left"
                Margin="12,12,0,0"
                Name="button1"
                VerticalAlignment="Top"
                Width="115"
                Click="button1_Click" />
        <Button Content="Muchas páginas"
                Height="47"
                HorizontalAlignment="Left"
                Margin="133,12,0,0"
                Name="button2"
                VerticalAlignment="Top"
                Width="115"
                Click="button2_Click" />
        <TextBlock Height="30"
                   HorizontalAlignment="Left"
                   Margin="14,70,0,0"
                   Name="textBlock1"
                   VerticalAlignment="Top"
                   Width="372"
                   FontSize="14" />
    </Grid>

Los botones nos servirán para mandar a imprimir por medio de la ejecución del método Print() de la clase PrintDocument y el TextBlock nos servirá para identificar el estatus de la impresión.

En el clic del primer botón crearemos una nueva instancia de PrintDocument y estableceremos su propiedad DocumentName de manera adecuada.  El valor de esta propiedad será lo que aparezca en la ventana de estado de la impresora.

PrintDocument pd = new PrintDocument() { DocumentName = "Ejemplo de Impresión" };

Ahora bien, manejaremos el evento PrintPage.  En este caso usaremos una expresión lambda pero pudiera ser también un método:

pd.PrintPage += (s, a) =>
            {
                //canvas es una variable a nivel de clase
                //Establecemos el ancho y alto de canvas a usando la propiedad PrintableArea
                canvas = new Canvas() { Width = a.PrintableArea.Width, Height = a.PrintableArea.Height };

                //Agregamos el título deseado para la página
                CrearTitulo("Esto es una Prueba de Impresión");

                //Establecemos el contenido en la propiedad PageVisual
                a.PageVisual = canvas;
            };

En el código anterior suceden varias cosas:

Creamos un objeto de tipo Canvas, el cual nos servirá como lienzo para dibujar en él los elementos visuales que queramos imprimir (en este ejemplo el contenido será un TextBlock creado en el método CrearTitulo()).  El ancho y alto del objeto Canvas los establecemos a partir de la propiedad PrintableArea, la cual, nos indica el tamaño de impresión según la impresora seleccionada (por ejemplo, el área de impresión es diferente en OneNote que un .xps).

Finalmente, establecemos este contenido que creamos dinámicamente en la propiedad PageVisual.  Esta propiedad indica el contenido visual que vamos a imprimir.  El siguiente fragmento de código contiene todo el código completo de este primer ejemplo:

Canvas canvas = null;
int pagina = 0;

private void button1_Click(object sender, RoutedEventArgs e)
{            
    PrintDocument pd = new PrintDocument() { DocumentName = "Ejemplo de Impresión" };
    pd.PrintPage += (s, a) =>
    {
        //canvas es una variable a nivel de clase
        //Establecemos el ancho y alto de canvas a usando la propiedad PrintableArea
        canvas = new Canvas() { Width = a.PrintableArea.Width, Height = a.PrintableArea.Height };

        //Agregamos el título deseado para la página
        CrearTitulo("Esto es una Prueba de Impresión");

        //Establecemos el contenido en la propiedad PageVisual
        a.PageVisual = canvas;
    };
    pd.StartPrint += (s, a) => textBlock1.Text = "Iniciando impresión…";
    pd.EndPrint += (s, a) => textBlock1.Text = "Impresión finalizada";
    pd.Print();
}

void CrearTitulo(string titulo)
{
    //Crea un TextBlock que servirá como encabezado
    TextBlock contenido = new TextBlock() { Text = titulo, FontSize = 20 };
    contenido.Effect = new DropShadowEffect();
    canvas.Children.Add(contenido);
    Canvas.SetLeft(contenido, canvas.Width / 2 – (contenido.ActualWidth / 2));
}

Y el resultado, tanto en un archivo .xps como en OneNote:

2 3

Noten cómo también soporta Efectos visuales.  Tal es el caso del DropShadowEffect que se está estableciendo en el título.

En el segundo botón tendremos una ligera variante: mandaremos a imprimir varias páginas.  Esto es logrado a partir de establecer la propiedad HasMorePages = true.  En el caso de este ejemplo hemos establecido una variable a nivel de clase llamada pagina que nos servirá de bandera.  Esta bandera la estaremos revisando hasta que se completen 4 páginas en total.

pd.PrintPage += (s, a) =>
            {
                canvas = new Canvas() { Width = a.PrintableArea.Width, Height = a.PrintableArea.Height };
                CrearTitulo("Esto es una Prueba de Impresión");
                CrearSubtitulo(string.Format("Página: {0}", pagina+1));
                a.PageVisual = canvas;

                a.HasMorePages = !(pagina == 3);
                pagina++;

            };

Cabe recordar que al establecer la propiedad HasMorePages a true, el evento PrintPage se vuelve a disparar, de esta manera, podemos tener el control del contenido a imprimir en cada página.  El código completo se muestra a continuación:

void CrearSubtitulo(string titulo)
        {
            //Crea un TextBlock que servirá como subtitulo
            TextBlock contenido = new TextBlock() { Text = titulo, FontSize = 14 };
            canvas.Children.Add(contenido);
            Canvas.SetLeft(contenido, canvas.Width / 2 – (contenido.ActualWidth / 2));
            Canvas.SetTop(contenido, 40);
        }

        private void button2_Click(object sender, RoutedEventArgs e)
        {
            PrintDocument pd = new PrintDocument() { DocumentName = "Ejemplo de Impresión" };
            pd.PrintPage += (s, a) =>
            {
                canvas = new Canvas() { Width = a.PrintableArea.Width, Height = a.PrintableArea.Height };
                CrearTitulo("Esto es una Prueba de Impresión");
                CrearSubtitulo(string.Format("Página: {0}", pagina+1));
                a.PageVisual = canvas;

                a.HasMorePages = !(pagina == 3);
                pagina++;

            };
            pd.StartPrint += (s, a) => textBlock1.Text = "Iniciando impresión…";
            pd.EndPrint += (s, a) => textBlock1.Text = "Impresión finalizada";
            pd.Print();
        }

El resultado final de la impresión de este segundo botón se muestra en la siguiente figura (las flechas rojas se añadieron posteriormente para indicar el número de cada página):

4

Resumen

Silverlight 4 Beta incluye la funcionalidad de impresión, a través de la clase System.Windows.Printing.PrintDocument.  Esta clase incluye el método Print(), que al ser ejecutado dispara una serie de eventos, entre ellos el evento PrintPage en donde podemos establecer el contenido deseado para imprimir, conocer el tamaño del área de impresión así como determinar si hay más páginas para imprimir (para escenarios de documentos de más de 1 página).

Puedes descargar el código aquí.

Puedes ver el demo en vivo aquí (requiere Silverlight 4 Beta instalado).

  • Share/Bookmark