Compartir a través de


Imprimir desde tu aplicación

En este tema se describe cómo imprimir desde una aplicación de Windows.

Para obtener características más avanzadas, consulte Personalización de la interfaz de usuario de vista previa de impresión.

Registro para imprimir

El primer paso para agregar impresión a la aplicación es registrarse para imprimir obteniendo el objeto PrintManager para la ventana actual. La clase PrintManager es responsable de orquestar el flujo de impresión de la aplicación. Para usar esta clase, primero debe llamar al método que devuelve el objeto PrintManager específico de la ventana activa actual.

La aplicación debe hacerlo en cada pantalla desde la que desea que el usuario pueda imprimir. Solo se puede registrar la pantalla que se muestra al usuario para imprimir. Si una pantalla de la aplicación se ha registrado para la impresión, debe anular el registro para imprimir cuando salga. Si se reemplaza por otra pantalla, la siguiente pantalla debe registrarse para imprimir cuando se abra.

Sugerencia

 Si necesitas admitir la impresión desde más de una página de la aplicación, puedes colocar este código de impresión en una clase auxiliar común y hacer que las páginas de la aplicación la reutilicen. Para obtener un ejemplo de cómo hacerlo, consulta la PrintHelper clase en el ejemplo de impresión de UWP.

Después de que un usuario haya iniciado la impresión, use printDocument para preparar las páginas que se enviarán a la impresora. El PrintDocument tipo está en el espacio de nombres Microsoft.UI.Xaml.Printing junto con otros tipos que admiten la preparación del contenido XAML para la impresión.

La clase PrintDocument se usa para controlar gran parte de la interacción entre la aplicación y printManager, pero expone varias devoluciones de llamada propias. Durante el registro, cree instancias de PrintManager y PrintDocument y registre controladores para sus eventos de impresión.

En este ejemplo, el registro se realiza en el RegisterForPrinting método , al que se llama desde el controlador de eventos Loaded de la página.

using Microsoft.UI.Xaml.Printing;
using Windows.Graphics.Printing;

PrintDocument printDocument = null;
IPrintDocumentSource printDocumentSource = null;
List<UIElement> printPreviewPages = new List<UIElement>();

private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
    RegisterForPrinting();
}

private void RegisterForPrinting()
{
    var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(App.MainWindow);
    PrintManager printManager = PrintManagerInterop.GetForWindow(hWnd);
    printManager.PrintTaskRequested += PrintTask_Requested;

    printDocument = new PrintDocument();
    printDocumentSource = printDocument.DocumentSource;
    printDocument.Paginate += PrintDocument_Paginate;
    printDocument.GetPreviewPage += PrintDocument_GetPreviewPage;
    printDocument.AddPages += PrintDocument_AddPages;
}

Advertencia

En los ejemplos de impresión de UWP, se recomienda registrarse para imprimir desde la invalidación del método OnNavigatedTo. En las aplicaciones que no son para UWP, debes usar el identificador de ventana en la llamada PrintManagerInterop.GetForWindow, por lo que debes usar el evento Loaded para asegurarte de que el identificador de la ventana no nullsea , que podría ser el caso en OnNavigatedTo.

Aquí, los controladores de eventos no se registran en el UnregisterForPrinting método , al que se llama desde el método OnNavigatedFrom .

protected override void OnNavigatedFrom(NavigationEventArgs e)
{
    base.OnNavigatedFrom(e);
    UnregisterForPrinting();
}


private void UnregisterForPrinting()
{
    if (printDocument == null)
    {
        return;
    }

    printDocument.Paginate -= PrintDocument_Paginate;
    printDocument.GetPreviewPage -= PrintDocument_GetPreviewPage;
    printDocument.AddPages -= PrintDocument_AddPages;

    var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(App.MainWindow);
    PrintManager printManager = PrintManagerInterop.GetForWindow(hWnd);
    printManager.PrintTaskRequested -= PrintTask_Requested;
}

Nota:

Si tiene una aplicación de varias páginas y no desconecta la impresión, se produce una excepción cuando el usuario deja la página y, a continuación, vuelve a ella.

Crear un botón de impresión

Agrega un botón de impresión a la pantalla de la aplicación donde quieres que aparezca. Asegúrese de que no interfiere con el contenido que desea imprimir.

<Button x:Name="InvokePrintingButton"
        Content="Print"
        Click="InvokePrintingButton_Click"/>

En el controlador de eventos Click del botón, muestre la interfaz de usuario de impresión de Windows al usuario.

var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(App.MainWindow);
await PrintManagerInterop.ShowPrintUIForWindowAsync(hWnd);

Este método es un método asincrónico que muestra la ventana de impresión adecuada, por lo que deberá agregar la palabra clave async al controlador Click. Se recomienda llamar primero al método IsSupported para comprobar que la aplicación se está ejecutando en un dispositivo que admita la impresión (y controle el caso en el que no lo es). Si la impresión no se puede realizar en ese momento por cualquier otro motivo, el método producirá una excepción. Se recomienda detectar estas excepciones y permitir al usuario saber cuándo no puede continuar la impresión.

En este ejemplo, se muestra una ventana de impresión en el controlador de eventos para un clic de botón. Si el método produce una excepción (porque no se puede realizar la impresión en ese momento), un control ContentDialog informa al usuario de la situación.

private async void InvokePrintingButton_Click(object sender, RoutedEventArgs e)
{
    if (PrintManager.IsSupported())
    {
        try
        {
            // Show system print UI.
            var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(App.MainWindow);
            await Windows.Graphics.Printing.PrintManagerInterop.ShowPrintUIForWindowAsync(hWnd);
        }
        catch
        {
            // Printing cannot proceed at this time.
            ContentDialog noPrintingDialog = new ContentDialog()
            {
                Title = "Printing error",
                Content = "\nSorry, printing can' t proceed at this time.",
                PrimaryButtonText = "OK"
            };
            await noPrintingDialog.ShowAsync();
        }
    }
    else
    {
        // Printing is not supported on this device.
        ContentDialog noPrintingDialog = new ContentDialog()
        {
            Title = "Printing not supported",
            Content = "\nSorry, printing is not supported on this device.",
            PrimaryButtonText = "OK"
        };
        await noPrintingDialog.ShowAsync();
    }
}

Dar formato al contenido de la aplicación

Cuando ShowPrintUIForWindowAsync se llama a , se genera el evento PrintTaskRequested . En el PrintTaskRequested controlador de eventos, se crea un PrintTask llamando al método PrintTaskRequest.CreatePrintTask . Pase el título de la página de impresión y el nombre de un delegado PrintTaskSourceRequestedHandler . El título se muestra en la interfaz de usuario de vista previa de impresión. Vincula PrintTaskSourceRequestedHandler con PrintTask el PrintDocument objeto que proporcionará el contenido.

En este ejemplo, también se define un controlador de finalización para detectar errores. Es una buena idea controlar los eventos de finalización porque, a continuación, la aplicación puede informar al usuario si se produjo un error y proporcionar posibles soluciones. Del mismo modo, la aplicación podría usar el evento de finalización para indicar los pasos posteriores que el usuario debe realizar después de que el trabajo de impresión se realice correctamente.

private void PrintTask_Requested(PrintManager sender, PrintTaskRequestedEventArgs args)
{
    // Create the PrintTask.
    // Defines the title and delegate for PrintTaskSourceRequested.
    PrintTask printTask = args.Request.CreatePrintTask("WinUI 3 Printing example", PrintTaskSourceRequested);

    // Handle PrintTask.Completed to catch failed print jobs.
    printTask.Completed += PrintTask_Completed;

    DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Normal, () =>
    {
        InvokePrintingButton.IsEnabled = false;
    });
}

private void PrintTaskSourceRequested(PrintTaskSourceRequestedArgs args)
{
    // Set the document source.
    args.SetSource(printDocumentSource);
}

private void PrintTask_Completed(PrintTask sender, PrintTaskCompletedEventArgs args)
{
    string StatusBlockText = string.Empty;

    // Notify the user if the print operation fails.
    if (args.Completion == PrintTaskCompletion.Failed)
    {
        StatusBlockText = "Failed to print.";
    }
    else if (args.Completion == PrintTaskCompletion.Canceled)
    {
        StatusBlockText = "Printing canceled.";
    }
    else
    {
        StatusBlockText = "Printing completed.";
    }


    DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Normal, () =>
    {
        StatusBlock.Text = StatusBlockText;
        InvokePrintingButton.IsEnabled = true;
    });
}

Una vez creada la tarea de impresión, PrintManager solicita una colección de páginas de impresión que se mostrarán en la interfaz de usuario de vista previa de impresión mediante la generación del evento Paginate . (Esto corresponde al Paginate método de la IPrintPreviewPageCollection interfaz). En este momento, se llama al controlador de eventos que creó durante el registro.

Importante

 Si el usuario cambia la configuración de impresión, se volverá a llamar al controlador de eventos paginado para permitirle volver a distribuir el contenido. Para obtener la mejor experiencia de usuario, se recomienda comprobar la configuración antes de volver a distribuir el contenido y evitar reinicializar el contenido paginado cuando no sea necesario.

En el controlador de eventos Paginate , cree las páginas que se mostrarán en la interfaz de usuario de vista previa de impresión y envíela a la impresora. El código que usas para preparar el contenido de la aplicación para imprimir es específico de la aplicación y del contenido que imprimes.

En este ejemplo se muestran los pasos básicos para crear una sola página de impresión que imprime una imagen y un título de la página que se muestra en la pantalla.

  • Cree una lista para contener los elementos de la interfaz de usuario (páginas) que se van a imprimir.
  • Borre la lista de páginas de vista previa para que las páginas no se dupliquen cada vez que se produzca la paginación.
  • Use PrintPageDescription para obtener el tamaño de la página de impresora.
  • Dar formato al contenido XAML para que se ajuste a la página de la impresora. Cada página que se va a imprimir es un elemento de interfaz de usuario XAML (normalmente un elemento contenedor que contiene otro contenido). En este ejemplo, los elementos se crean en el código y usan los mismos datos que los elementos que se muestran en la pantalla.
  • Fluya el contenido a páginas adicionales según sea necesario. No se muestran varias páginas en este ejemplo básico, pero dividir el contenido en páginas es una parte importante del evento Paginate.
  • Agregue cada página a la lista de páginas que se van a imprimir.
  • Establezca el recuento de páginas de vista previa en PrintDocument.
List<UIElement> printPreviewPages = new List<UIElement>();

private void PrintDocument_Paginate(object sender, PaginateEventArgs e)
{
    // Clear the cache of preview pages.
    printPreviewPages.Clear();

    // Get the PrintTaskOptions.
    PrintTaskOptions printingOptions = ((PrintTaskOptions)e.PrintTaskOptions);
    // Get the page description to determine the size of the print page.
    PrintPageDescription pageDescription = printingOptions.GetPageDescription(0);

    // Create the print layout.
    StackPanel printLayout = new StackPanel();
    printLayout.Width = pageDescription.PageSize.Width;
    printLayout.Height = pageDescription.PageSize.Height;
    printLayout.BorderBrush = new Microsoft.UI.Xaml.Media.SolidColorBrush(Microsoft.UI.Colors.Black);
    printLayout.BorderThickness = new Thickness(48);

    Image printImage = new Image();
    printImage.Source = printContent.Source;

    printImage.Width = pageDescription.PageSize.Width / 2;
    printImage.Height = pageDescription.PageSize.Height / 2;

    TextBlock imageDescriptionText = new TextBlock();
    imageDescriptionText.Text = imageDescription.Text;
    imageDescriptionText.FontSize = 24;
    imageDescriptionText.HorizontalAlignment = HorizontalAlignment.Center;
    imageDescriptionText.Width = pageDescription.PageSize.Width / 2;
    imageDescriptionText.TextWrapping = TextWrapping.WrapWholeWords;

    printLayout.Children.Add(printImage);
    printLayout.Children.Add(imageDescriptionText);

    // Add the print layout to the list of preview pages.
    printPreviewPages.Add(printLayout);

    // Report the number of preview pages created.
    PrintDocument printDocument = (PrintDocument)sender;
    printDocument.SetPreviewPageCount(printPreviewPages.Count,
                                          PreviewPageCountType.Intermediate);
}

Esta es una captura de pantalla de la interfaz de usuario de la aplicación y cómo aparece el contenido en la interfaz de usuario de vista previa de impresión.

Captura de pantalla de una interfaz de usuario de aplicación junto a la interfaz de usuario de vista previa de impresión del sistema, en la que se muestra una imagen y un título que se imprimirán.

Cuando se va a mostrar una página determinada en la ventana vista previa de impresión, PrintManager genera el evento GetPreviewPage . Esto corresponde al MakePage método de la IPrintPreviewPageCollection interfaz . En este momento, se llama al controlador de eventos que creó durante el registro.

En el controlador de eventos GetPreviewPage , establezca la página adecuada en el documento de impresión.

private void PrintDocument_GetPreviewPage(object sender, GetPreviewPageEventArgs e)
{
    PrintDocument printDocument = (PrintDocument)sender;
    printDocument.SetPreviewPage(e.PageNumber, printPreviewPages[e.PageNumber - 1]);
}

Por último, una vez que el usuario hace clic en el botón imprimir, PrintManager solicita la colección final de páginas para enviar a la impresora llamando al MakeDocument método de la IDocumentPageSource interfaz. En XAML, esto genera el evento AddPages . En este momento, se llama al controlador de eventos que creó durante el registro.

En el controlador de eventos AddPages , agregue páginas de la colección de páginas al objeto PrintDocument que se enviará a la impresora. Si un usuario especifica páginas concretas o un intervalo de páginas que se van a imprimir, use esa información aquí para agregar solo las páginas que realmente se enviarán a la impresora.

private void PrintDocument_AddPages(object sender, AddPagesEventArgs e)
{
    PrintDocument printDocument = (PrintDocument)sender;

    // Loop over all of the preview pages and add each one to be printed.
    for (int i = 0; i < printPreviewPages.Count; i++)
    {
        printDocument.AddPage(printPreviewPages[i]);
    }

    // Indicate that all of the print pages have been provided.
    printDocument.AddPagesComplete();
}