Печать из приложения
В этом разделе описывается печать из приложения Windows.
Дополнительные возможности см. в разделе "Настройка пользовательского интерфейса предварительной версии печати".
- Важные API: пространство имен Windows.Graphics.Printing, класс PrintManager, PrintTask, пространство имен Microsoft.UI.Xaml.Printing, класс PrintDocument
Регистрация для печати
Первым шагом для добавления печати в приложение является регистрация для печати путем получения объекта PrintManager для текущего окна. Класс PrintManager отвечает за оркестрацию потока печати для приложения. Чтобы использовать этот класс, необходимо сначала вызвать метод, возвращающий объект PrintManager, относящееся к текущему активному окну.
- В приложении, отличном от UWP, используйте метод PrintManagerInterop.GetForWindow .
- В приложении UWP используйте метод PrintManager.GetForCurrentView .
Приложение должно сделать это на каждом экране, с которого вы хотите, чтобы пользователь мог распечатать. Для печати можно зарегистрировать только экран, отображаемый пользователю. Если один экран приложения зарегистрирован для печати, он должен отменить регистрацию для печати при выходе. Если он заменен другим экраном, следующий экран должен зарегистрировать для печати при открытии.
Совет
Если вам нужно поддерживать печать с нескольких страниц в приложении, этот код печати можно поместить в общий вспомогательный класс и повторно использовать страницы приложения. Пример этого см PrintHelper
. в классе в примере печати UWP.
После того как пользователь инициировал печать, вы используете PrintDocument для подготовки страниц, которые будут отправлены на принтер. Тип PrintDocument
находится в пространстве имен Microsoft.UI.Xaml.Printing вместе с другими типами, поддерживающими подготовку содержимого XAML для печати.
Класс PrintDocument используется для обработки большого количества взаимодействия между приложением и PrintManager, но предоставляет несколько обратных вызовов. Во время регистрации создайте экземпляры и PrintDocument
обработчики PrintManager
регистрации для их событий печати.
В этом примере регистрация выполняется в методе RegisterForPrinting
, который вызывается из обработчика событий loaded страницы.
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;
}
Предупреждение
В примерах печати UWP рекомендуется зарегистрировать для печати из переопределения метода OnNavigatedTo. В приложениях, отличных от UWP, необходимо использовать дескриптор окна в вызове PrintManagerInterop.GetForWindow, поэтому следует использовать событие Loaded, чтобы убедиться, что дескриптор окна не null
имеет значения, что может быть в OnNavigatedTo.
Здесь обработчики событий отменяются в методе UnregisterForPrinting
, который вызывается из метода 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;
}
Примечание.
Если у вас есть приложение с несколькими страницами и не отключает печать, исключение возникает, когда пользователь покидает страницу, а затем возвращается к нему.
Создание кнопки печати
Добавьте кнопку печати на экран приложения, в котором она будет отображаться. Убедитесь, что оно не влияет на содержимое, которое требуется распечатать.
<Button x:Name="InvokePrintingButton"
Content="Print"
Click="InvokePrintingButton_Click"/>
В обработчике событий нажатия кнопки отобразится пользовательский интерфейс печати Windows пользователю.
- В приложении, отличном от UWP, используйте метод PrintManagerInterop.ShowPrintUIForWindowAsync .
- В приложении UWP используйте метод PrintManager.ShowPrintUIAsync .
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(App.MainWindow);
await PrintManagerInterop.ShowPrintUIForWindowAsync(hWnd);
Этот метод является асинхронным методом, который отображает соответствующее окно печати, поэтому необходимо добавить асинхронное ключевое слово в обработчик Click. Рекомендуется сначала вызвать метод IsSupported , чтобы убедиться, что приложение выполняется на устройстве, поддерживающем печать (и обрабатывайте ситуацию, в которой она отсутствует). Если печать не может быть выполнена в то время по какой-либо другой причине, метод вызовет исключение. Мы рекомендуем перехватывать эти исключения и сообщить пользователю, когда печать не может продолжиться.
В этом примере окно печати отображается в обработчике событий для нажатия кнопки. Если метод создает исключение (так как печать не может быть выполнена в то время), элемент управления ContentDialog сообщает пользователю о ситуации.
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();
}
}
Форматирование содержимого приложения
При ShowPrintUIForWindowAsync
вызове вызывается событие PrintTaskRequested . В обработчике событий создайте PrintTask, вызвав метод PrintTaskRequest.CreatePrintTask.PrintTaskRequested
Передайте заголовок страницы печати и имя делегата PrintTaskSourceRequestedHandler . Заголовок отображается в пользовательском интерфейсе предварительного просмотра печати. Ссылки PrintTaskSourceRequestedHandler
PrintTask
на PrintDocument
содержимое.
В этом примере обработчик завершения также определяется для перехвата ошибок. Рекомендуется обрабатывать события завершения, так как приложение может сообщить пользователю, что произошла ошибка и предоставить возможные решения. Аналогичным образом, приложение может использовать событие завершения, чтобы указать последующие шаги, которые пользователь может предпринять после успешного задания печати.
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;
});
}
После создания задачи печати PrintManager запрашивает коллекцию страниц печати, чтобы отобразиться в пользовательском интерфейсе предварительного просмотра печати, вызвав событие Paginate. (Это соответствует Paginate
методу IPrintPreviewPageCollection
интерфейса.) В настоящее время вызывается обработчик событий, созданный во время регистрации.
Внимание
Если пользователь изменяет параметры печати, обработчик событий paginate будет вызываться снова, чтобы разрешить перенаправлять содержимое. Для лучшего взаимодействия с пользователем рекомендуется проверить параметры перед перерасходом содержимого и избежать повторной инициализации содержимого с разбивкой на страницы, если это не обязательно.
В обработчике событий Paginate создайте страницы для отображения в пользовательском интерфейсе предварительного просмотра печати и отправки на принтер. Код, используемый для подготовки содержимого приложения для печати, зависит от вашего приложения и содержимого, которое вы печатаете.
В этом примере показаны основные шаги по созданию одной страницы печати, которая печатает изображение и подпись на странице, показанной на экране.
- Создайте список для печати элементов пользовательского интерфейса (страниц).
- Снимите список страниц предварительного просмотра, чтобы страницы не повторялись при каждом возникновении разбиения на страницы.
- Используйте PrintPageDescription, чтобы получить размер страницы принтера.
- Отформатируйте содержимое XAML, чтобы он соответствовал странице принтера. Каждая страница для печати — это элемент пользовательского интерфейса XAML (обычно элемент контейнера, содержащий другое содержимое). В этом примере элементы создаются в коде и используют те же данные, что и элементы, отображаемые на экране.
- При необходимости перенесите содержимое на дополнительные страницы. В этом базовом примере не отображаются несколько страниц, но разделение содержимого на страницы является важной частью события Paginate.
- Добавьте каждую страницу в список страниц для печати.
- Задайте количество страниц предварительного просмотра в 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);
}
Ниже приведен снимок экрана пользовательского интерфейса приложения и способ отображения содержимого в пользовательском интерфейсе предварительного просмотра печати.
При отображении определенной страницы в окне предварительного просмотра печати диспетчер PrintManager вызывает событие GetPreviewPage . Это соответствует MakePage
методу IPrintPreviewPageCollection
интерфейса. В настоящее время вызывается обработчик событий, созданный во время регистрации.
В обработчике событий GetPreviewPage задайте соответствующую страницу в документе печати.
private void PrintDocument_GetPreviewPage(object sender, GetPreviewPageEventArgs e)
{
PrintDocument printDocument = (PrintDocument)sender;
printDocument.SetPreviewPage(e.PageNumber, printPreviewPages[e.PageNumber - 1]);
}
Наконец, когда пользователь нажимает кнопку печати, PrintManager запрашивает окончательную коллекцию страниц для отправки на принтер путем вызова MakeDocument
метода IDocumentPageSource
интерфейса. В XAML это вызывает событие AddPages . В настоящее время вызывается обработчик событий, созданный во время регистрации.
В обработчике событий AddPages добавьте страницы из коллекции страниц в объект PrintDocument для отправки на принтер. Если пользователь указывает определенные страницы или диапазон страниц для печати, используйте эту информацию здесь, чтобы добавить только страницы, которые будут отправляться на принтер.
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();
}
См. также
Windows developer