Compartilhar via


Imprimir de seu app

Este tópico descreve como imprimir de um aplicativo do Windows.

Para obter recursos mais avançados, consulte Personalizar a interface do usuário de visualização de impressão.

Registre-se para impressão

A primeira etapa para adicionar impressão ao seu aplicativo é registrar-se para impressão obtendo o objeto PrintManager para a janela atual. A classe PrintManager é responsável por orquestrar o fluxo de impressão do seu aplicativo. Para usar essa classe, você deve primeiro chamar o método que retorna o objeto PrintManager específico da janela ativa atual.

Seu aplicativo deve fazer isso em todas as telas das quais você deseja que o usuário possa imprimir. Somente a tela exibida para o usuário pode ser registrada para impressão. Se uma tela do seu aplicativo tiver sido registrada para impressão, ela deverá cancelar o registro para impressão quando for encerrada. Se for substituído por outra tela, a próxima tela deverá ser registrada para impressão quando for aberta.

Dica

 Se você precisar dar suporte à impressão de mais de uma página em seu aplicativo, poderá colocar esse código de impressão em uma classe auxiliar comum e fazer com que as páginas do aplicativo o reutilizem. Para obter um exemplo de como fazer isso, consulte a PrintHelper classe no exemplo de impressão UWP.

Depois que um usuário inicia a impressão, você usa um PrintDocument para preparar as páginas a serem enviadas para a impressora. O PrintDocument tipo está no namespace Microsoft.UI.Xaml.Printing junto com outros tipos que dão suporte à preparação de conteúdo XAML para impressão.

A classe PrintDocument é usada para lidar com grande parte da interação entre o aplicativo e o PrintManager, mas expõe vários retornos de chamada próprios. Durante o registro, crie instâncias de PrintManager e PrintDocument e registre manipuladores para seus eventos de impressão.

Neste exemplo, o RegisterForPrinting registro é executado no método, que é chamado do manipulador de eventos Loaded da 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;
}

Aviso

Em exemplos de impressão UWP, é recomendável se registrar para impressão da substituição do método OnNavigatedTo. Em aplicativos não UWP, você precisa usar o identificador de janela na chamada PrintManagerInterop.GetForWindow, portanto, você deve usar o evento Loaded para garantir que o identificador de janela não nullseja , o que pode ser o caso em OnNavigatedTo.

Aqui, os manipuladores de eventos não são registrados no UnregisterForPrinting método, que é chamado do 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;
}

Observação

Se você tiver um aplicativo de várias páginas e não desconectar a impressão, uma exceção será gerada quando o usuário sair da página e retornar a ela.

Criar um botão de impressão

Adicione um botão de impressão à tela do seu aplicativo onde você gostaria que ele aparecesse. Certifique-se de que não interfere com o conteúdo que pretende imprimir.

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

No manipulador de eventos Click do Button, mostre a interface do usuário de impressão do Windows para o usuário.

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

Esse método é um método assíncrono que exibe a janela de impressão apropriada, portanto, você precisará adicionar a palavra-chave assíncrona ao manipulador de cliques. É recomendável chamar o método IsSupported primeiro para verificar se o aplicativo está sendo executado em um dispositivo que dá suporte à impressão (e lidar com o caso em que não está). Se a impressão não puder ser executada naquele momento por qualquer outro motivo, o método gerará uma exceção. Recomendamos capturar essas exceções e informar ao usuário quando a impressão não puder continuar.

Neste exemplo, uma janela de impressão é exibida no manipulador de eventos para um clique de botão. Se o método gerar uma exceção (porque a impressão não pode ser executada naquele momento), um controle ContentDialog informará o usuário sobre a situação.

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();
    }
}

Formatar o conteúdo do seu aplicativo

Quando ShowPrintUIForWindowAsync é chamado, o evento PrintTaskRequested é gerado. No manipulador de PrintTaskRequested eventos, você cria um PrintTask chamando o método PrintTaskRequest.CreatePrintTask . Passe o título da página de impressão e o nome de um representante PrintTaskSourceRequestedHandler . O título é mostrado na interface do usuário de visualização de impressão. Os PrintTaskSourceRequestedHandler links com PrintTask o PrintDocument que fornecerá o conteúdo.

Neste exemplo, um manipulador de conclusão também é definido para capturar erros. É uma boa ideia lidar com eventos de conclusão porque seu aplicativo pode informar ao usuário se ocorreu um erro e fornecer possíveis soluções. Da mesma forma, seu aplicativo pode usar o evento completion para indicar as etapas subsequentes a serem executadas pelo usuário após o trabalho de impressão ser bem-sucedido.

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;
    });
}

Depois que a tarefa de impressão é criada, o PrintManager solicita uma coleção de páginas de impressão para mostrar na interface do usuário de visualização de impressão gerando o evento Paginate. (Isso corresponde ao Paginate IPrintPreviewPageCollection método da interface.) O manipulador de eventos que você criou durante o registro é chamado neste momento.

Importante

 Se o usuário alterar as configurações de impressão, o manipulador de eventos paginate será chamado novamente para permitir que você reflua o conteúdo. Para obter a melhor experiência do usuário, recomendamos verificar as configurações antes de refluir o conteúdo e evitar reinicializar o conteúdo paginado quando não for necessário.

No manipulador de eventos Paginate , crie as páginas a serem mostradas na interface do usuário de visualização de impressão e enviadas para a impressora. O código usado para preparar o conteúdo do aplicativo para impressão é específico do aplicativo e do conteúdo impresso.

Este exemplo mostra as etapas básicas para criar uma única página de impressão que imprime uma imagem e uma legenda da página mostrada na tela.

  • Crie uma lista para conter os elementos da interface do usuário (páginas) a serem impressos.
  • Limpe a lista de páginas de visualização para que as páginas não sejam duplicadas sempre que ocorrer a paginação.
  • Use o PrintPageDescription para obter o tamanho da página da impressora.
  • Formate o conteúdo XAML para caber na página da impressora. Cada página a ser impressa é um elemento de interface do usuário XAML (normalmente um elemento de contêiner que contém outro conteúdo). Neste exemplo, os elementos são criados no código e usam os mesmos dados que os elementos mostrados na tela.
  • Flua o conteúdo para páginas adicionais conforme necessário. Várias páginas não são mostradas neste exemplo básico, mas dividir o conteúdo em páginas é uma parte importante do evento Paginate.
  • Adicione cada página à lista de páginas a serem impressas.
  • Defina a contagem de páginas de visualização no 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);
}

Aqui está uma captura de tela da interface do usuário do aplicativo e como o conteúdo aparece na interface do usuário de visualização de impressão.

Uma captura de tela de uma interface do usuário do aplicativo ao lado da interface do usuário de visualização de impressão do sistema, mostrando uma imagem e uma legenda a serem impressas.

Quando uma página específica deve ser mostrada na janela de visualização de impressão, o PrintManager gera o evento GetPreviewPage . Isso corresponde ao MakePage método da IPrintPreviewPageCollection interface. O manipulador de eventos que você criou durante o registro é chamado neste momento.

No manipulador de eventos GetPreviewPage , defina a página apropriada no documento de impressão.

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

Por fim, quando o usuário clica no botão de impressão, o PrintManager solicita a coleção final de páginas a serem enviadas à impressora chamando o MakeDocument método da IDocumentPageSource interface. Em XAML, isso gera o evento AddPages . O manipulador de eventos que você criou durante o registro é chamado neste momento.

No manipulador de eventos AddPages, adicione páginas da coleção de páginas ao objeto PrintDocument a ser enviado para a impressora. Se um usuário especificar páginas específicas ou um intervalo de páginas para imprimir, use essas informações aqui para adicionar apenas as páginas que serão realmente enviadas para a impressora.

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();
}