Stampare dall'app

Questo argomento descrive come stampare da un'app di Windows universale.

Per funzionalità più avanzate, vedere Personalizza l'interfaccia utente dell'anteprima di stampa.

API importanti

Suggerimento

 La maggior parte degli esempi in questo argomento si basa sull'Esempio di stampa piattaforma UWP (Universal Windows Platform), che fa parte del repository di Esempi di app Universal Windows Platform (UWP) su GitHub.

Registrarsi per la stampa

Il primo passaggio per aggiungere la stampa all'app consiste nel registrarsi per il contratto di stampa. L'app deve eseguire questa operazione in ogni schermata da cui si vuole che l'utente possa stampare. Solo la schermata visualizzata all'utente può essere registrata per la stampa. Se una schermata dell'app è stata registrata per la stampa, deve annullare la registrazione per la stampa all'uscita. Se viene sostituito da un'altra schermata, la schermata successiva deve registrarsi per un nuovo contratto di stampa all'apertura.

Suggerimento

 Qualora sia necessario supportare la stampa da più pagine nella propria app, è possibile inserire questo codice di stampa in una classe helper comune e riutilizzare le pagine dell'app. Per un esempio di come eseguire questa operazione, vedere la PrintHelper classe in Esempio di stampa UWP.

Prima di tutto, dichiarare PrintManager e PrintDocument. Il tipo PrintManager si trova nello spazio dei nomi Windows.Graphics.Printing insieme ai tipi per supportare altre funzionalità di stampa di Windows. Il tipo PrintDocument si trova nello spazio dei nomi Windows.UI.Xaml.Printing insieme ad altri tipi che supportano la preparazione del contenuto XAML per la stampa. È possibile semplificare la scrittura del codice di stampa aggiungendo le seguenti istruzioni using or Importazioni alla pagina.

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

La classe PrintDocument viene usata per gestire gran parte dell'interazione tra l'app e PrintManager, ma espone diversi propri callback. Durante la registrazione, creare istanze di PrintManager e PrintDocument e registrare i gestori per gli eventi di stampa.

Nell'Esempio di stampa UWP, la registrazione viene eseguita dal metodo RegisterForPrinting.

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

Quando l'utente passa a una pagina che supporta la stampa, avvia la registrazione all'interno del metodo OnNavigatedTo.

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

Nell'esempio i gestori eventi non vengono registrati nel metodo UnregisterForPrinting.

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

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

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

Quando l'utente abbandona una pagina che supporta la stampa, i gestori eventi non vengono registrati all'interno del metodo OnNavigatedFrom.

Nota

Se si dispone di un'app a più pagine e non si scollega la stampa, viene lanciata un'eccezione quando l'utente abbandona la pagina e poi vi ritorna.

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

Creare un pulsante di stampa

Aggiungere un pulsante di stampa alla schermata dell'app in cui si vuole visualizzarla. Assicurarsi che non interferisca con il contenuto che si desidera stampare.

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

Aggiungere quindi un gestore eventi al codice dell'app per gestire l'evento click. Usare il metodo ShowPrintUIAsync per avviare la stampa dall'app. ShowPrintUIAsync è un metodo asincrono che visualizza la finestra di stampa appropriata. È consigliabile richiamare prima il metodo IsSupported per verificare che l'app venga eseguita in un dispositivo che supporta la stampa (e gestire il caso in cui non lo è). Se non è possibile eseguire la stampa in quel momento per qualsiasi altro motivo, ShowPrintUIAsync genererà un'eccezione. È consigliabile intercettare queste eccezioni e consentire all'utente di sapere quando la stampa non può continuare.

In questo esempio viene visualizzata una finestra di stampa nel gestore eventi per un clic su un pulsante. Se il metodo genera un'eccezione (perché la stampa non può essere eseguita in quel momento), un controllo ContentDialog informa l'utente della situazione.

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

Formattare il contenuto dell'app

Quando viene richiamato ShowPrintUIAsync, si genera l'evento PrintTaskRequested. Il gestore eventi PrintTaskRequested illustrato in questo passaggio crea un PrintTask richiamando il metodo PrintTaskRequest.CreatePrintTask passa il titolo per la pagina di stampa e il nome di un delegato PrintTaskSourceRequestedHandler. Si noti che in questo esempio printTaskSourceRequestedHandler viene definito inline. Il PrintTaskSourceRequestedHandler fornisce il contenuto formattato per la stampa e viene descritto più avanti.

In questo esempio viene definito anche un gestore di completamento per rilevare gli errori. È consigliabile gestire gli eventi di completamento perché l'app può comunicare all'utente se si è verificato un errore e fornire possibili soluzioni. Analogamente, l'app potrebbe usare l'evento di completamento per indicare i passaggi successivi che l'utente deve eseguire al termine del processo di stampa.

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

Dopo aver creato l'attività di stampa, PrintManager richiede una raccolta di pagine di stampa da visualizzare nell'interfaccia utente dell'anteprima di stampa generando l'evento Impagina. Corrisponde al metodo Impagina dell'interfaccia IPrintPreviewPageCollection. Il gestore eventi creato durante la registrazione verrà chiamato in questo momento.

Importante

 Se l'utente modifica le impostazioni di stampa, il gestore eventi impaginato verrà richiamato di nuovo per consentire la rielaborazione del contenuto. Per un'esperienza utente ottimale, è consigliabile controllare le impostazioni prima di rielaborare il contenuto ed evitare di reinizializzare il contenuto impaginato quando non è necessario.

Nel gestore eventi Impagina (il metodo CreatePrintPreviewPages dell'Esempio stampa UWP), creare le pagine da visualizzare nell'interfaccia utente dell'anteprima di stampa e inviare alla stampante. Il codice usato per preparare il contenuto dell'app per la stampa è specifico per l'app e per il contenuto stampato. Fare riferimento al codice sorgente Esempio di stampa UWP per vedere come formatta il contenuto per la stampa.

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

Quando una determinata pagina deve essere visualizzata nella finestra di anteprima di stampa, PrintManager richiama l'evento GetPreviewPage. Corrisponde al metodo MakePage dell'interfaccia IPrintPreviewPageCollection. Il gestore eventi creato durante la registrazione verrà chiamato in questo momento.

Nel gestore eventi GetPreviewPage (il GetPrintPreviewPage metodo dell'Esempio di stampa UWP), impostare la pagina appropriata sul documento di stampa.

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

Infine, quando l'utente seleziona con un clic il pulsante di stampa, PrintManager richiede l'insieme finale di pagine da inviare alla stampante richiamando il metodo MakeDocument dell'interfaccia IDocumentPageSource. In XAML viene generato l'evento AddPages . Il gestore eventi creato durante la registrazione verrà chiamato in questo momento.

Nel gestore eventi AddPages (il AddPrintPages metodo nell'Esempio di stampa UWP), aggiungere pagine dalla raccolta di pagine all'oggetto PrintDocument da inviare alla stampante. Se un utente specifica pagine particolari o un intervallo di pagine da stampare, utilizzare tali informazioni qui per aggiungere solo le pagine che verranno effettivamente inviate alla stampante.

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

Preparare le opzioni di stampa

Preparare quindi le opzioni di stampa. Ad esempio, questa sezione descrive come impostare l'opzione intervallo di pagine per consentire la stampa di pagine specifiche. Per opzioni più avanzate, vedere Personalizza l'interfaccia utente dell'anteprima di stampa.

Questo passaggio crea una nuova opzione di stampa, definisce un elenco di valori supportati dall'opzione e quindi aggiunge quest'ultima all'interfaccia utente dell'anteprima di stampa. L'opzione intervallo di pagine include queste impostazioni:

Nome opzione Azione
Stampa tutto Stampare tutte le pagine del documento.
Selezione di stampa Stampa solo il contenuto selezionato dall'utente.
Intervallo di stampa Consente di visualizzare un controllo di modifica in cui l'utente può immettere le pagine da stampare.

In primo luogo, modificare il gestore eventi PrintTaskRequested per aggiungere il codice per ottenere un oggetto PrintTaskOptionDetails.

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

Poi, deselezionare l'elenco delle opzioni visualizzate nell'interfaccia utente dell'anteprima di stampa e aggiungere le opzioni da visualizzare quando l'utente vuole stampare dall'app.

Nota

 Le opzioni vengono visualizzate nell'interfaccia utente dell'anteprima di stampa nello stesso ordine in cui vengono aggiunte, con la prima opzione visualizzata nella parte superiore della finestra.

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

Creare la nuova opzione di stampa e inizializzare l'elenco di valori di opzione.

// 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");

Aggiungere l'opzione di stampa personalizzata e assegnare il gestore eventi. L'opzione personalizzata viene aggiunta per ultima in modo che venga visualizzata nella parte inferiore dell'elenco di opzioni. Tuttavia è possibile inserirlo in qualsiasi punto dell'elenco, per cui non è necessario aggiungere opzioni di stampa personalizzate per ultimo.

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

Il metodo CreateTextOption crea la casella di testo Intervallo . In questo caso l'utente immette le pagine specifiche da stampare quando selezionano l'opzione Intervallo di stampa.

Gestisci le modifiche alle opzioni di stampa

Il gestore eventi OptionChanged esegue due operazioni. In primo luogo, mostra e nasconde il campo di modifica del testo per l'intervallo di pagine a seconda dell'opzione intervallo di pagine selezionata dall'utente. In secondo luogo, verificare che il testo inserito nella casella di testo dell'intervallo di pagine rappresenti un intervallo di pagine valido per il documento.

Questo esempio mostra come vengono gestiti gli eventi di modifica delle opzioni di stampa nell'Esempio di stampa UWP.

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

Suggerimento

 Vedere il metodo GetPagesInRange nell' Esempio di stampa UWP per informazioni dettagliate su come analizzare l'intervallo di pagine immesso dall'utente nella casella di testo Intervallo.

Visualizza in anteprima le pagine selezionate

La modalità di formattazione del contenuto dell'app per la stampa dipende dalla natura dell'app e dal relativo contenuto. Una classe helper di stampa utilizzata nell'Esempio di stampa UWP per formattare il contenuto per la stampa.

Quando si stampa un subset di pagine, è possibile visualizzare il contenuto nell'anteprima di stampa in diversi modi. Indipendentemente dal metodo scelto per visualizzare l'intervallo di pagine nell'anteprima di stampa, l'output stampato deve contenere solo le pagine selezionate.

  • Mostra tutte le pagine nell'anteprima di stampa, indipendentemente dal fatto che sia specificato o meno un intervallo di pagine, lasciando all'utente la possibilità di sapere quali pagine verranno effettivamente stampate.
  • Mostra solo le pagine selezionate dall'intervallo di pagine dell'utente nell'anteprima di stampa, aggiornando la visualizzazione ogni volta che l'utente modifica l'intervallo di pagine.
  • Mostra tutte le pagine nell'anteprima di stampa, ma oscura le pagine non incluse nell'intervallo di pagine selezionato dall'utente.