Drucken in Apps

In diesem Thema wird beschrieben, wie Sie aus einer Windows-App drucken.

Weitere erweiterte Features finden Sie unter Anpassen der Druckvorschau-Benutzeroberfläche.

Registrieren für das Drucken

Der erste Schritt zum Hinzufügen des Druckens zu Ihrer App besteht darin, das PrintManager-Objekt für das aktuelle Fenster zu registrieren. Die PrintManager-Klasse ist für die Orchestrierung des Druckflusses für Ihre App verantwortlich. Um diese Klasse zu verwenden, müssen Sie zuerst die Methode aufrufen, die das PrintManager-Objekt zurückgibt, das für das aktuelle aktive Fenster spezifisch ist.

Die App muss dies auf jedem Bildschirm ausführen, von dem der Benutzer drucken kann. Nur der Bildschirm, der für den Benutzer angezeigt wird, kann für den Druck registriert werden. Wenn sich ein Bildschirm Ihrer App für den Druck registriert hat, muss sie die Registrierung für den Druck aufheben, wenn sie beendet wird. Wenn sie durch einen anderen Bildschirm ersetzt wird, muss sich der nächste Bildschirm beim Öffnen für den Druck registrieren.

Tipp

 Wenn Sie das Drucken von mehr als einer Seite in Ihrer App unterstützen müssen, können Sie diesen Druckcode in eine gängige Hilfsklasse einfügen und ihre App-Seiten wiederverwenden lassen. Ein Beispiel dafür finden Sie in der PrintHelper Klasse im UWP-Druckbeispiel.

Nachdem ein Benutzer den Druck initiiert hat, verwenden Sie ein PrintDocument , um die Seiten vorzubereiten, die an den Drucker gesendet werden sollen. Der PrintDocument Typ befindet sich im Microsoft.UI.Xaml.Printing-Namespace zusammen mit anderen Typen, die die Vorbereitung von XAML-Inhalten für das Drucken unterstützen.

Die PrintDocument-Klasse wird verwendet, um einen Großteil der Interaktion zwischen der App und dem PrintManager zu behandeln, stellt jedoch mehrere Rückrufe selbst zur Verfügung. Erstellen Sie während der Registrierung Instanzen von PrintManager und PrintDocument registrieren Sie Handler für ihre Druckereignisse.

In diesem Beispiel wird die Registrierung in der RegisterForPrinting Methode ausgeführt, die vom Loaded-Ereignishandler der Seite aufgerufen wird.

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

Warnung

In UWP-Druckbeispielen wird empfohlen, das Drucken über die OnNavigatedTo-Methode außer Kraft zu setzen. In Nicht-UWP-Apps müssen Sie das Fensterhandle im PrintManagerInterop.GetForWindow-Aufruf verwenden, daher sollten Sie das Loaded-Ereignis verwenden, um sicherzustellen, dass das Fensterhandle nicht null, was in OnNavigatedTo der Fall sein könnte.

Hier werden die Ereignishandler in der UnregisterForPrinting Methode nicht registriert, die von der OnNavigatedFrom-Methode aufgerufen wird.

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

Hinweis

Wenn Sie über eine Mehrseiten-App verfügen und das Drucken nicht trennen, wird eine Ausnahme ausgelöst, wenn der Benutzer die Seite verlässt und dann wieder darauf zurückkehrt.

Erstellen einer Druckschaltfläche

Fügen Sie dem Bildschirm Ihrer App eine Druckschaltfläche hinzu, auf der sie angezeigt werden soll. Stellen Sie sicher, dass der Inhalt, den Sie drucken möchten, nicht beeinträchtigt wird.

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

Zeigen Sie im Click-Ereignishandler der Schaltfläche dem Benutzer die Windows-Druckoberfläche an.

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

Diese Methode ist eine asynchrone Methode, die das entsprechende Druckfenster anzeigt. Daher müssen Sie dem Click-Handler das asynchrone Schlüsselwort hinzufügen. Es wird empfohlen, zuerst die IsSupported-Methode aufzurufen, um zu überprüfen, ob die App auf einem Gerät ausgeführt wird, das das Drucken unterstützt (und den Fall behandelt, in dem dies nicht der Fall ist). Wenn das Drucken zu diesem Zeitpunkt aus einem anderen Grund nicht ausgeführt werden kann, löst die Methode eine Ausnahme aus. Es wird empfohlen, diese Ausnahmen abzufangen und dem Benutzer mitzuteilen, wenn der Druckvorgang nicht fortgesetzt werden kann.

In diesem Beispiel wird ein Druckfenster im Ereignishandler für einen Schaltflächenklick angezeigt. Wenn die Methode eine Ausnahme auslöst (da das Drucken zu diesem Zeitpunkt nicht ausgeführt werden kann), informiert ein ContentDialog-Steuerelement den Benutzer über die Situation.

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

Formatieren der App-Inhalte

Beim ShowPrintUIForWindowAsync Aufruf wird das PrintTaskRequested-Ereignis ausgelöst. PrintTaskRequested Im Ereignishandler erstellen Sie eine PrintTask, indem Sie die PrintTaskRequest.CreatePrintTask-Methode aufrufen. Übergeben Sie den Titel für die Druckseite und den Namen eines PrintTaskSourceRequestedHandler-Delegaten . Der Titel wird in der Druckvorschau-Benutzeroberfläche angezeigt. Die PrintTaskSourceRequestedHandler Links werden PrintTask mit dem PrintDocument Inhalt verknüpft.

In diesem Beispiel wird auch ein Abschlusshandler definiert, um Fehler abzufangen. Es ist ratsam, Abschlussereignisse zu behandeln, da die App dem Benutzer mitteilen kann, ob ein Fehler aufgetreten ist und mögliche Lösungen bereitstellt. Ebenso könnte Ihre App das Abschlussereignis verwenden, um nachfolgende Schritte anzugeben, die der Benutzer ausführen kann, nachdem der Druckauftrag erfolgreich war.

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

Nachdem die Druckaufgabe erstellt wurde, fordert printManager eine Sammlung von Druckseiten an, die in der Druckvorschau-Benutzeroberfläche angezeigt werden, indem das Paginate-Ereignis ausgelöst wird. (Dies entspricht der Paginate Methode der IPrintPreviewPageCollection Schnittstelle.) Der ereignishandler, den Sie während der Registrierung erstellt haben, wird zurzeit aufgerufen.

Wichtig

 Wenn der Benutzer Druckeinstellungen ändert, wird der Paginate-Ereignishandler erneut aufgerufen, damit Sie den Inhalt umbrechen können. Um eine optimale Benutzererfahrung zu erzielen, empfehlen wir, die Einstellungen zu überprüfen, bevor Sie den Inhalt umbrechen und vermeiden, dass der seitenaufgesetzte Inhalt erneut initialisiert wird, wenn er nicht erforderlich ist.

Erstellen Sie im Paginate-Ereignishandler die Seiten, die in der Druckvorschau-Benutzeroberfläche angezeigt werden sollen, und senden Sie sie an den Drucker. Der Code, den Sie zum Vorbereiten des App-Inhalts zum Drucken verwenden, ist spezifisch für Ihre App und den inhalt, den Sie drucken.

Dieses Beispiel zeigt die grundlegenden Schritte zum Erstellen einer einzelnen Druckseite, die ein Bild und eine Beschriftung von der auf dem Bildschirm angezeigten Seite druckt.

  • Erstellen Sie eine Liste, die die zu druckden UI-Elemente (Seiten) enthält.
  • Löschen Sie die Liste der Vorschauseiten, sodass Seiten nicht jedes Mal dupliziert werden, wenn die Paginierung auftritt.
  • Verwenden Sie printPageDescription, um die Größe der Druckerseite abzurufen.
  • Formatieren Sie Ihren XAML-Inhalt so, dass er auf die Druckerseite passt. Jede zu druckde Seite ist ein XAML-UI-Element (in der Regel ein Containerelement, das andere Inhalte enthält). In diesem Beispiel werden Elemente im Code erstellt und verwenden dieselben Daten wie die auf dem Bildschirm angezeigten Elemente.
  • Fließen Sie den Inhalt nach Bedarf auf zusätzlichen Seiten. In diesem einfachen Beispiel werden nicht mehrere Seiten gezeigt, aber das Aufteilen des Inhalts in Seiten ist ein wichtiger Bestandteil des Paginate-Ereignisses.
  • Fügen Sie jede Seite zur Liste der zu druckende Seiten hinzu.
  • Legen Sie die Anzahl der Vorschauseiten im PrintDocument fest.
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);
}

Hier sehen Sie einen Screenshot der App-UI und die Darstellung des Inhalts in der Druckvorschau-UI.

Screenshot einer App-UI neben der Benutzeroberfläche für die Systemdruckvorschau mit einem Bild und einer Beschriftung, die gedruckt werden soll.

Wenn eine bestimmte Seite im Fenster "Seitenansicht" angezeigt werden soll, löst printManager das GetPreviewPage-Ereignis aus. Dies entspricht der MakePage Methode der IPrintPreviewPageCollection Schnittstelle. Der ereignishandler, den Sie während der Registrierung erstellt haben, wird zurzeit aufgerufen.

Legen Sie im GetPreviewPage-Ereignishandler die entsprechende Seite im Druckdokument fest.

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

Nachdem der Benutzer auf die Druckschaltfläche klickt, fordert der PrintManager die endgültige Sammlung von Seiten an, die an den Drucker gesendet werden sollen, indem die MakeDocument Methode der IDocumentPageSource Schnittstelle aufgerufen wird. In XAML löst dies das AddPages-Ereignis aus. Der ereignishandler, den Sie während der Registrierung erstellt haben, wird zurzeit aufgerufen.

Fügen Sie im AddPages-Ereignishandler Seiten aus der Seitenauflistung zum PrintDocument-Objekt hinzu, das an den Drucker gesendet werden soll. Wenn ein Benutzer bestimmte Seiten oder einen zu druckende Seitenbereich angibt, verwenden Sie diese Informationen hier, um nur die Seiten hinzuzufügen, die tatsächlich an den Drucker gesendet werden.

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