Stampare dall'app
Questo argomento descrive come stampare da un'app di Windows.
Per funzionalità più avanzate, vedere Personalizza l'interfaccia utente dell'anteprima di stampa.
- API importanti: spazio dei nomi Windows.Graphics.Printing, classe PrintManager, PrintTask, Spazio dei nomi Microsoft.UI.Xaml.Printing, classe PrintDocument
Registrarsi per la stampa
Il primo passaggio per aggiungere la stampa all'app consiste nel registrarsi per la stampa recuperando l'oggetto PrintManager per la finestra corrente. La classe PrintManager è responsabile dell'orchestrazione del flusso di stampa per l'app. Per utilizzare questa classe, è prima necessario chiamare il metodo che restituisce l'oggetto PrintManager specifico della finestra attiva corrente.
- In un'app non UWP usare il metodo PrintManagerInterop.GetForWindow .
- In un'app UWP usa il metodo PrintManager.GetForCurrentView .
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 la 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.
Dopo che un utente ha avviato la stampa, utilizzare printDocument per preparare le pagine da inviare alla stampante. Il PrintDocument
tipo si trova nello spazio dei nomi Microsoft.UI.Xaml.Printing insieme ad altri tipi che supportano la preparazione del contenuto XAML per la stampa.
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 e PrintDocument
registrare i gestori per gli eventi di PrintManager
stampa.
In questo esempio la registrazione viene eseguita nel RegisterForPrinting
metodo , che viene chiamato dal gestore eventi Loaded della pagina.
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;
}
Avviso
Negli esempi di stampa UWP è consigliabile registrarsi per la stampa dall'override del metodo OnNavigatedTo. Nelle app non UWP devi usare l'handle di finestra nella chiamata PrintManagerInterop.GetForWindow, quindi devi usare l'evento Loaded per assicurarti che l'handle della finestra non null
sia , che potrebbe essere il caso in OnNavigatedTo.
In questo caso, i gestori eventi vengono annullati la registrazione nel UnregisterForPrinting
metodo , che viene chiamato dal metodo 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
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.
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="InvokePrintingButton_Click"/>
Nel gestore dell'evento Click del pulsante visualizzare l'interfaccia utente di stampa di Windows all'utente.
- In un'app non UWP usare il metodo PrintManagerInterop.ShowPrintUIForWindowAsync .
- In un'app UWP usa il metodo PrintManager.ShowPrintUIAsync .
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(App.MainWindow);
await PrintManagerInterop.ShowPrintUIForWindowAsync(hWnd);
Questo metodo è un metodo asincrono che visualizza la finestra di stampa appropriata, quindi è necessario aggiungere la parola chiave asincrona al gestore Click. È 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, il metodo 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.
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();
}
}
Formattare il contenuto dell'app
Quando ShowPrintUIForWindowAsync
viene chiamato, viene generato l'evento PrintTaskRequested . PrintTaskRequested
Nel gestore eventi si crea un printTask chiamando il metodo PrintTaskRequest.CreatePrintTaskTask. Passare il titolo per la pagina di stampa e il nome di un delegato PrintTaskSourceRequestedHandler . Il titolo viene visualizzato nell'interfaccia utente dell'anteprima di stampa. PrintTaskSourceRequestedHandler
Collega l'oggetto PrintTask
PrintDocument
con che fornirà il contenuto.
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.
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;
});
}
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 Paginate
metodo dell'interfaccia IPrintPreviewPageCollection
. Al momento viene chiamato il gestore eventi creato durante la registrazione.
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 Paginate 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.
In questo esempio vengono illustrati i passaggi di base per creare una singola pagina di stampa che stampa un'immagine e una didascalia dalla pagina visualizzata sullo schermo.
- Creare un elenco per contenere gli elementi dell'interfaccia utente (pagine) da stampare.
- Cancellare l'elenco delle pagine di anteprima in modo che le pagine non siano duplicate ogni volta che viene eseguita la paginazione.
- Utilizzare PrintPageDescription per ottenere le dimensioni della pagina della stampante.
- Formattare il contenuto XAML in base alla pagina della stampante. Ogni pagina da stampare è un elemento dell'interfaccia utente XAML (in genere un elemento contenitore che contiene altri contenuti). In questo esempio gli elementi vengono creati nel codice e usano gli stessi dati degli elementi visualizzati sullo schermo.
- Propagare il contenuto in pagine aggiuntive in base alle esigenze. In questo esempio di base non vengono visualizzate più pagine, ma la suddivisione del contenuto in pagine è una parte importante dell'evento Paginate.
- Aggiungere ogni pagina all'elenco di pagine da stampare.
- Impostare il numero di pagine di anteprima in 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);
}
Ecco uno screenshot dell'interfaccia utente dell'app e il modo in cui il contenuto viene visualizzato nell'interfaccia utente dell'anteprima di stampa.
Quando una determinata pagina deve essere visualizzata nella finestra di anteprima di stampa, PrintManager richiama l'evento GetPreviewPage. Corrisponde al MakePage
metodo dell'interfaccia IPrintPreviewPageCollection
. Al momento viene chiamato il gestore eventi creato durante la registrazione.
Nel gestore eventi GetPreviewPage impostare la pagina appropriata nel documento di stampa.
private void PrintDocument_GetPreviewPage(object sender, GetPreviewPageEventArgs e)
{
PrintDocument printDocument = (PrintDocument)sender;
printDocument.SetPreviewPage(e.PageNumber, printPreviewPages[e.PageNumber - 1]);
}
Infine, quando l'utente fa clic sul pulsante di stampa, PrintManager richiede la raccolta finale di pagine da inviare alla stampante chiamando il MakeDocument
metodo dell'interfaccia IDocumentPageSource
. In XAML viene generato l'evento AddPages . Al momento viene chiamato il gestore eventi creato durante la registrazione.
Nel gestore eventi AddPages aggiungere pagine dall'insieme 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.
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();
}