Freigeben über


Drucken in Apps

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

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

Wichtige APIs

Tipp

 Die meisten Beispiele in diesem Thema basieren auf dem Druckbeispiel Universelle Windows-Plattform (UWP), das Teil des Repositorys für Universelle Windows-Plattform -Apps (UWP) auf GitHub ist.

Registrieren für das Drucken

Der erste Schritt zum Hinzufügen des Druckens zu Ihrer App besteht darin, sich für den Vertrag für "Drucken" zu registrieren. 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 einen neuen Vertrag für "Drucken" 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.

Deklarieren Sie zuerst "PrintManager" und "PrintDocument". Der PrintManager-Typ befindet sich im Windows.Graphics.Printing-Namespace zusammen mit Typen zur Unterstützung anderer Windows-Druckfunktionen. Der PrintDocument-Typ befindet sich im Windows.UI.Xaml.Printing-Namespace zusammen mit anderen Typen, die das Vorbereiten von XAML-Inhalten für das Drucken unterstützen. Sie können das Schreiben des Druckcodes vereinfachen, indem Sie ihrer Seite die folgenden Anweisungen hinzufügen.

using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

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 , und registrieren Sie Handler für ihre Druckereignisse.

Im UWP-Druckbeispiel wird die Registrierung durch die RegisterForPrinting Methode ausgeführt.

public virtual void RegisterForPrinting()
{
   printDocument = new PrintDocument();
   printDocumentSource = printDocument.DocumentSource;
   printDocument.Paginate += CreatePrintPreviewPages;
   printDocument.GetPreviewPage += GetPrintPreviewPage;
   printDocument.AddPages += AddPrintPages;

   PrintManager printMan = PrintManager.GetForCurrentView();
   printMan.PrintTaskRequested += PrintTaskRequested;
}

Wenn der Benutzer zu einer Seite wechselt, die das Drucken unterstützt, wird die Registrierung innerhalb der OnNavigatedTo Methode initiiert.

protected override void OnNavigatedTo(NavigationEventArgs e)
{
   // Initialize common helper class and register for printing
   printHelper = new PrintHelper(this);
   printHelper.RegisterForPrinting();

   // Initialize print content for this scenario
   printHelper.PreparePrintContent(new PageToPrint());

   // Tell the user how to print
   MainPage.Current.NotifyUser("Print contract registered with customization, use the Print button to print.", NotifyType.StatusMessage);
}

Im Beispiel werden die Ereignishandler in der UnregisterForPrinting Methode nicht registriert.

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

    printDocument.Paginate -= CreatePrintPreviewPages;
    printDocument.GetPreviewPage -= GetPrintPreviewPage;
    printDocument.AddPages -= AddPrintPages;

    PrintManager printMan = PrintManager.GetForCurrentView();
    printMan.PrintTaskRequested -= PrintTaskRequested;
}

Wenn der Benutzer eine Seite verlässt, die das Drucken unterstützt, werden die Ereignishandler innerhalb der OnNavigatedFrom Methode nicht registriert.

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.

protected override void OnNavigatedFrom(NavigationEventArgs e)
{
   if (printHelper != null)
   {
         printHelper.UnregisterForPrinting();
   }
}

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="OnPrintButtonClick"/>

Fügen Sie als Nächstes einen Ereignishandler zum Behandeln des Click-Ereignisses zu Ihrem App-Code hinzu. Verwenden Sie die ShowPrintUIAsync-Methode , um mit dem Drucken aus Ihrer App zu beginnen. ShowPrintUIAsync ist eine asynchrone Methode, die das entsprechende Druckfenster anzeigt. 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 ShowPrintUIAsync 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.

async private void OnPrintButtonClick(object sender, RoutedEventArgs e)
{
    if (Windows.Graphics.Printing.PrintManager.IsSupported())
    {
        try
        {
            // Show print UI
            await Windows.Graphics.Printing.PrintManager.ShowPrintUIAsync();

        }
        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

Wenn ShowPrintUIAsync aufgerufen wird, wird das PrintTaskRequested-Ereignis ausgelöst. Der in diesem Schritt gezeigte PrintTaskRequested-Ereignishandler erstellt eine PrintTask durch Aufrufen der PrintTaskRequest.CreatePrintTask-Methode und übergibt den Titel für die Druckseite und den Namen eines PrintTaskSourceRequestedHandler-Delegaten. Beachten Sie, dass in diesem Beispiel der PrintTaskSourceRequestedHandler inline definiert ist. Der PrintTaskSourceRequestedHandler stellt den formatierten Inhalt zum Drucken bereit und wird später beschrieben.

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.

protected virtual void PrintTaskRequested(PrintManager sender, PrintTaskRequestedEventArgs e)
{
   PrintTask printTask = null;
   printTask = e.Request.CreatePrintTask("C# Printing SDK Sample", sourceRequested =>
   {
         // Print Task event handler is invoked when the print job is completed.
         printTask.Completed += async (s, args) =>
         {
            // Notify the user when the print operation fails.
            if (args.Completion == PrintTaskCompletion.Failed)
            {
               await scenarioPage.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
               {
                     MainPage.Current.NotifyUser("Failed to print.", NotifyType.ErrorMessage);
               });
            }
         };

         sourceRequested.SetSource(printDocumentSource);
   });
}

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 CreatePrintPreviewPages Methode im UWP-Druckbeispiel) die Seiten, die in der Druckvorschau-Benutzeroberfläche angezeigt werden sollen, und senden 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. Im UWP-Druckbeispielquellcode erfahren Sie, wie der Inhalt für das Drucken formatiert wird.

protected virtual void CreatePrintPreviewPages(object sender, PaginateEventArgs e)
{
   // Clear the cache of preview pages
   printPreviewPages.Clear();

   // Clear the print canvas of preview pages
   PrintCanvas.Children.Clear();

   // This variable keeps track of the last RichTextBlockOverflow element that was added to a page which will be printed
   RichTextBlockOverflow lastRTBOOnPage;

   // Get the PrintTaskOptions
   PrintTaskOptions printingOptions = ((PrintTaskOptions)e.PrintTaskOptions);

   // Get the page description to deterimine how big the page is
   PrintPageDescription pageDescription = printingOptions.GetPageDescription(0);

   // We know there is at least one page to be printed. passing null as the first parameter to
   // AddOnePrintPreviewPage tells the function to add the first page.
   lastRTBOOnPage = AddOnePrintPreviewPage(null, pageDescription);

   // We know there are more pages to be added as long as the last RichTextBoxOverflow added to a print preview
   // page has extra content
   while (lastRTBOOnPage.HasOverflowContent && lastRTBOOnPage.Visibility == Windows.UI.Xaml.Visibility.Visible)
   {
         lastRTBOOnPage = AddOnePrintPreviewPage(lastRTBOOnPage, pageDescription);
   }

   if (PreviewPagesCreated != null)
   {
         PreviewPagesCreated.Invoke(printPreviewPages, null);
   }

   PrintDocument printDoc = (PrintDocument)sender;

   // Report the number of preview pages created
   printDoc.SetPreviewPageCount(printPreviewPages.Count, PreviewPageCountType.Intermediate);
}

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 GetPrintPreviewPage Methode im UWP-Druckbeispiel) die entsprechende Seite im Druckdokument fest.

protected virtual void GetPrintPreviewPage(object sender, GetPreviewPageEventArgs e)
{
   PrintDocument printDoc = (PrintDocument)sender;
   printDoc.SetPreviewPage(e.PageNumber, printPreviewPages[e.PageNumber - 1]);
}

Nachdem der Benutzer auf die Druckschaltfläche klickt, fordert 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 (die AddPrintPages Methode im UWP-Druckbeispiel) 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.

protected virtual void AddPrintPages(object sender, AddPagesEventArgs e)
{
   // Loop over all of the preview pages and add each one to  add each page to be printied
   for (int i = 0; i < printPreviewPages.Count; i++)
   {
         // We should have all pages ready at this point...
         printDocument.AddPage(printPreviewPages[i]);
   }

   PrintDocument printDoc = (PrintDocument)sender;

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

Vorbereiten von Druckoptionen

Bereiten Sie als Nächstes Druckoptionen vor. In diesem Abschnitt wird beispielsweise beschrieben, wie sie die Seitenbereichsoption festlegen, um das Drucken bestimmter Seiten zu ermöglichen. Weitere erweiterte Optionen finden Sie unter Anpassen der Druckvorschau-Benutzeroberfläche.

In diesem Schritt wird eine neue Druckoption erstellt, eine Liste mit Werten definiert, die von der Option unterstützt werden, und anschließend wird der Druckvorschau-Benutzeroberfläche die Option hinzugefügt. Die Option "Seitenbereich" hat die folgenden Einstellungen:

Name der Option Aktion
Alles drucken Drucken sie alle Seiten im Dokument.
Auswahl drucken Drucken Sie nur den Inhalt, den der Benutzer ausgewählt hat.
Druckbereich Zeigt ein Bearbeitungssteuerelement an, in das der Benutzer die zu druckden Seiten eingeben kann.

Ändern Sie zunächst den PrintTaskRequested-Ereignishandler , um den Code zum Abrufen eines PrintTaskOptionDetails-Objekts hinzuzufügen.

PrintTaskOptionDetails printDetailedOptions = PrintTaskOptionDetails.GetFromPrintTaskOptions(printTask.Options);

Löschen Sie die Liste der Optionen, die in der Druckvorschau-Benutzeroberfläche angezeigt werden, und fügen Sie die Optionen hinzu, die angezeigt werden sollen, wenn der Benutzer aus der App drucken möchte.

Hinweis

 Die Optionen werden in der Druckvorschau-Ui in derselben Reihenfolge angezeigt, in der sie angefügt werden, wobei die erste Option oben im Fenster angezeigt wird.

IList<string> displayedOptions = printDetailedOptions.DisplayedOptions;

displayedOptions.Clear();
displayedOptions.Add(Windows.Graphics.Printing.StandardPrintTaskOptions.Copies);
displayedOptions.Add(Windows.Graphics.Printing.StandardPrintTaskOptions.Orientation);
displayedOptions.Add(Windows.Graphics.Printing.StandardPrintTaskOptions.ColorMode);

Erstellen Sie die neue Druckoption, und initialisieren Sie die Liste der Optionswerte.

// Create a new list option
PrintCustomItemListOptionDetails pageFormat = printDetailedOptions.CreateItemListOption("PageRange", "Page Range");
pageFormat.AddItem("PrintAll", "Print all");
pageFormat.AddItem("PrintSelection", "Print Selection");
pageFormat.AddItem("PrintRange", "Print Range");

Fügen Sie Die benutzerdefinierte Druckoption hinzu, und weisen Sie den Ereignishandler zu. Die benutzerdefinierte Option wird zuletzt angefügt, sodass sie am Ende der Liste der Optionen angezeigt wird. Sie können sie aber an einer beliebigen Stelle in der Liste platzieren, benutzerdefinierte Druckoptionen müssen nicht zuletzt hinzugefügt werden.

// Add the custom option to the option list
displayedOptions.Add("PageRange");

// Create new edit option
PrintCustomTextOptionDetails pageRangeEdit = printDetailedOptions.CreateTextOption("PageRangeEdit", "Range");

// Register the handler for the option change event
printDetailedOptions.OptionChanged += printDetailedOptions_OptionChanged;

Die CreateTextOption-Methode erstellt das Textfeld Range . Hier gibt der Benutzer die spezifischen Seiten ein, die er drucken möchte, wenn er die Option "Druckbereich " auswählt.

Behandeln von Druckoptionsänderungen

Der OptionChanged-Ereignishandler führt zwei Dinge aus. Zunächst wird das Textbearbeitungsfeld für den Seitenbereich angezeigt und ausgeblendet, abhängig von der vom Benutzer ausgewählten Seitenbereichsoption. Zweitens wird der in das Textfeld für den Seitenbereich eingegebene Text überprüft, um sicherzustellen, dass er einen gültigen Seitenbereich für das Dokument darstellt.

In diesem Beispiel wird gezeigt, wie Druckoptionsänderungsereignisse im UWP-Druckbeispiel behandelt werden.

async void printDetailedOptions_OptionChanged(PrintTaskOptionDetails sender, PrintTaskOptionChangedEventArgs args)
{
   if (args.OptionId == null)
   {
         return;
   }

   string optionId = args.OptionId.ToString();

   // Handle change in Page Range Option
   if (optionId == "PageRange")
   {
         IPrintOptionDetails pageRange = sender.Options[optionId];
         string pageRangeValue = pageRange.Value.ToString();

         selectionMode = false;

         switch (pageRangeValue)
         {
            case "PrintRange":
               // Add PageRangeEdit custom option to the option list
               sender.DisplayedOptions.Add("PageRangeEdit");
               pageRangeEditVisible = true;
               await scenarioPage.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
               {
                     ShowContent(null);
               });
               break;
            case "PrintSelection":
               await scenarioPage.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
               {
                     Scenario4PageRange page = (Scenario4PageRange)scenarioPage;
                     PageToPrint pageContent = (PageToPrint)page.PrintFrame.Content;
                     ShowContent(pageContent.TextContentBlock.SelectedText);
               });
               RemovePageRangeEdit(sender);
               break;
            default:
               await scenarioPage.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
               {
                     ShowContent(null);
               });
               RemovePageRangeEdit(sender);
               break;
         }

         Refresh();
   }
   else if (optionId == "PageRangeEdit")
   {
         IPrintOptionDetails pageRange = sender.Options[optionId];
         // Expected range format (p1,p2...)*, (p3-p9)* ...
         if (!Regex.IsMatch(pageRange.Value.ToString(), @"^\s*\d+\s*(\-\s*\d+\s*)?(\,\s*\d+\s*(\-\s*\d+\s*)?)*$"))
         {
            pageRange.ErrorText = "Invalid Page Range (eg: 1-3, 5)";
         }
         else
         {
            pageRange.ErrorText = string.Empty;
            try
            {
               GetPagesInRange(pageRange.Value.ToString());
               Refresh();
            }
            catch (InvalidPageException ipex)
            {
               pageRange.ErrorText = ipex.Message;
            }
         }
   }
}

Tipp

 Ausführliche Informationen zum Analysieren des Seitenbereichs, den der Benutzer in das Textfeld "Bereich" eingibt, finden Sie in der GetPagesInRange Methode im UWP-Druckbeispiel .

Vorschau ausgewählter Seiten

Wie Sie den Inhalt Ihrer App für den Druck formatieren, hängt von der Art der App und des zugehörigen Inhalts ab. Eine Druckhilfsklasse, die im UWP-Druckbeispiel verwendet wird, um den Inhalt für den Druck zu formatieren.

Beim Drucken einer Teilmenge von Seiten gibt es mehrere Möglichkeiten, den Inhalt in der Seitenansicht anzuzeigen. Unabhängig von der Methode, die Sie für die Anzeige des Seitenbereichs in der Druckvorschau ausgewählt haben, darf die gedruckte Ausgabe nur die ausgewählten Seiten enthalten.

  • Zeigen Sie alle Seiten in der Seitenansicht an, ob ein Seitenbereich angegeben ist, oder nicht, sodass der Benutzer weiß, welche Seiten tatsächlich gedruckt werden.
  • Zeigen Sie nur die Seiten an, die vom Seitenbereich des Benutzers in der Seitenansicht ausgewählt wurden, und aktualisieren Sie die Anzeige, wenn der Benutzer den Seitenbereich ändert.
  • Zeigen Sie alle Seiten in der Seitenansicht an, aber blenden Sie die Seiten aus, die sich nicht im vom Benutzer ausgewählten Seitenbereich befinden.