Imprimir desde tu aplicación
En este tema se describe cómo imprimir desde una aplicación de Windows.
Para obtener características más avanzadas, consulte Personalización de la interfaz de usuario de vista previa de impresión.
- API importantes: Espacio de nombres Windows.Graphics.Printing, clase PrintManager, PrintTask, Espacio de nombres Microsoft.UI.Xaml.Printing, clase PrintDocument
Registro para imprimir
El primer paso para agregar impresión a la aplicación es registrarse para imprimir obteniendo el objeto PrintManager para la ventana actual. La clase PrintManager es responsable de orquestar el flujo de impresión de la aplicación. Para usar esta clase, primero debe llamar al método que devuelve el objeto PrintManager específico de la ventana activa actual.
- En una aplicación que no sea para UWP, usa el método PrintManagerInterop.GetForWindow .
- En una aplicación para UWP, usa el método PrintManager.GetForCurrentView .
La aplicación debe hacerlo en cada pantalla desde la que desea que el usuario pueda imprimir. Solo se puede registrar la pantalla que se muestra al usuario para imprimir. Si una pantalla de la aplicación se ha registrado para la impresión, debe anular el registro para imprimir cuando salga. Si se reemplaza por otra pantalla, la siguiente pantalla debe registrarse para imprimir cuando se abra.
Sugerencia
Si necesitas admitir la impresión desde más de una página de la aplicación, puedes colocar este código de impresión en una clase auxiliar común y hacer que las páginas de la aplicación la reutilicen. Para obtener un ejemplo de cómo hacerlo, consulta la PrintHelper
clase en el ejemplo de impresión de UWP.
Después de que un usuario haya iniciado la impresión, use printDocument para preparar las páginas que se enviarán a la impresora. El PrintDocument
tipo está en el espacio de nombres Microsoft.UI.Xaml.Printing junto con otros tipos que admiten la preparación del contenido XAML para la impresión.
La clase PrintDocument se usa para controlar gran parte de la interacción entre la aplicación y printManager, pero expone varias devoluciones de llamada propias. Durante el registro, cree instancias de PrintManager
y PrintDocument
y registre controladores para sus eventos de impresión.
En este ejemplo, el registro se realiza en el RegisterForPrinting
método , al que se llama desde el controlador de eventos Loaded de la 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;
}
Advertencia
En los ejemplos de impresión de UWP, se recomienda registrarse para imprimir desde la invalidación del método OnNavigatedTo. En las aplicaciones que no son para UWP, debes usar el identificador de ventana en la llamada PrintManagerInterop.GetForWindow, por lo que debes usar el evento Loaded para asegurarte de que el identificador de la ventana no null
sea , que podría ser el caso en OnNavigatedTo.
Aquí, los controladores de eventos no se registran en el UnregisterForPrinting
método , al que se llama desde el 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;
}
Nota:
Si tiene una aplicación de varias páginas y no desconecta la impresión, se produce una excepción cuando el usuario deja la página y, a continuación, vuelve a ella.
Crear un botón de impresión
Agrega un botón de impresión a la pantalla de la aplicación donde quieres que aparezca. Asegúrese de que no interfiere con el contenido que desea imprimir.
<Button x:Name="InvokePrintingButton"
Content="Print"
Click="InvokePrintingButton_Click"/>
En el controlador de eventos Click del botón, muestre la interfaz de usuario de impresión de Windows al usuario.
- En una aplicación que no sea para UWP, usa el método PrintManagerInterop.ShowPrintUIForWindowAsync .
- En una aplicación para UWP, usa el método PrintManager.ShowPrintUIAsync .
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(App.MainWindow);
await PrintManagerInterop.ShowPrintUIForWindowAsync(hWnd);
Este método es un método asincrónico que muestra la ventana de impresión adecuada, por lo que deberá agregar la palabra clave async al controlador Click. Se recomienda llamar primero al método IsSupported para comprobar que la aplicación se está ejecutando en un dispositivo que admita la impresión (y controle el caso en el que no lo es). Si la impresión no se puede realizar en ese momento por cualquier otro motivo, el método producirá una excepción. Se recomienda detectar estas excepciones y permitir al usuario saber cuándo no puede continuar la impresión.
En este ejemplo, se muestra una ventana de impresión en el controlador de eventos para un clic de botón. Si el método produce una excepción (porque no se puede realizar la impresión en ese momento), un control ContentDialog informa al usuario de la situación.
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();
}
}
Dar formato al contenido de la aplicación
Cuando ShowPrintUIForWindowAsync
se llama a , se genera el evento PrintTaskRequested . En el PrintTaskRequested
controlador de eventos, se crea un PrintTask llamando al método PrintTaskRequest.CreatePrintTask . Pase el título de la página de impresión y el nombre de un delegado PrintTaskSourceRequestedHandler . El título se muestra en la interfaz de usuario de vista previa de impresión. Vincula PrintTaskSourceRequestedHandler
con PrintTask
el PrintDocument
objeto que proporcionará el contenido.
En este ejemplo, también se define un controlador de finalización para detectar errores. Es una buena idea controlar los eventos de finalización porque, a continuación, la aplicación puede informar al usuario si se produjo un error y proporcionar posibles soluciones. Del mismo modo, la aplicación podría usar el evento de finalización para indicar los pasos posteriores que el usuario debe realizar después de que el trabajo de impresión se realice correctamente.
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;
});
}
Una vez creada la tarea de impresión, PrintManager solicita una colección de páginas de impresión que se mostrarán en la interfaz de usuario de vista previa de impresión mediante la generación del evento Paginate . (Esto corresponde al Paginate
método de la IPrintPreviewPageCollection
interfaz). En este momento, se llama al controlador de eventos que creó durante el registro.
Importante
Si el usuario cambia la configuración de impresión, se volverá a llamar al controlador de eventos paginado para permitirle volver a distribuir el contenido. Para obtener la mejor experiencia de usuario, se recomienda comprobar la configuración antes de volver a distribuir el contenido y evitar reinicializar el contenido paginado cuando no sea necesario.
En el controlador de eventos Paginate , cree las páginas que se mostrarán en la interfaz de usuario de vista previa de impresión y envíela a la impresora. El código que usas para preparar el contenido de la aplicación para imprimir es específico de la aplicación y del contenido que imprimes.
En este ejemplo se muestran los pasos básicos para crear una sola página de impresión que imprime una imagen y un título de la página que se muestra en la pantalla.
- Cree una lista para contener los elementos de la interfaz de usuario (páginas) que se van a imprimir.
- Borre la lista de páginas de vista previa para que las páginas no se dupliquen cada vez que se produzca la paginación.
- Use PrintPageDescription para obtener el tamaño de la página de impresora.
- Dar formato al contenido XAML para que se ajuste a la página de la impresora. Cada página que se va a imprimir es un elemento de interfaz de usuario XAML (normalmente un elemento contenedor que contiene otro contenido). En este ejemplo, los elementos se crean en el código y usan los mismos datos que los elementos que se muestran en la pantalla.
- Fluya el contenido a páginas adicionales según sea necesario. No se muestran varias páginas en este ejemplo básico, pero dividir el contenido en páginas es una parte importante del evento Paginate.
- Agregue cada página a la lista de páginas que se van a imprimir.
- Establezca el recuento de páginas de vista previa en 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);
}
Esta es una captura de pantalla de la interfaz de usuario de la aplicación y cómo aparece el contenido en la interfaz de usuario de vista previa de impresión.
Cuando se va a mostrar una página determinada en la ventana vista previa de impresión, PrintManager genera el evento GetPreviewPage . Esto corresponde al MakePage
método de la IPrintPreviewPageCollection
interfaz . En este momento, se llama al controlador de eventos que creó durante el registro.
En el controlador de eventos GetPreviewPage , establezca la página adecuada en el documento de impresión.
private void PrintDocument_GetPreviewPage(object sender, GetPreviewPageEventArgs e)
{
PrintDocument printDocument = (PrintDocument)sender;
printDocument.SetPreviewPage(e.PageNumber, printPreviewPages[e.PageNumber - 1]);
}
Por último, una vez que el usuario hace clic en el botón imprimir, PrintManager solicita la colección final de páginas para enviar a la impresora llamando al MakeDocument
método de la IDocumentPageSource
interfaz. En XAML, esto genera el evento AddPages . En este momento, se llama al controlador de eventos que creó durante el registro.
En el controlador de eventos AddPages , agregue páginas de la colección de páginas al objeto PrintDocument que se enviará a la impresora. Si un usuario especifica páginas concretas o un intervalo de páginas que se van a imprimir, use esa información aquí para agregar solo las páginas que realmente se enviarán a la impresora.
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();
}