Настройка рабочего процесса печати

Создавайте пользовательские рабочие процессы печати с помощью приложения для рабочих процессов печати.

Обзор

Приложения рабочих процессов печати — это приложения UWP, которые расширяют функциональные возможности приложений приложений устройств Microsoft Store (WSDAs), поэтому вам будет полезно ознакомиться с WSDAs, прежде чем идти дальше.

Так же, как и в случае WSDAs, когда пользователь исходного приложения выбирает печать и переходит через диалоговое окно печати, система проверяет, связано ли приложение рабочего процесса с этим принтером. Если это так, приложение рабочего процесса печати запускается (в первую очередь в качестве фоновой задачи; подробнее об этом ниже). Приложение рабочего процесса может изменить запрос печати (XML-документ, который настраивает параметры устройства принтера для текущей задачи печати) и фактическое содержимое XPS для печати. Кроме того, он может предоставить эту функцию пользователю, запустив пользовательский интерфейс в середине процесса. После выполнения своей работы, он передает содержимое для печати и билет на печать водителю.

Поскольку он включает фоновые и передние компоненты, а также поскольку он функционально связан с другими приложениями, приложение рабочего процесса печати может быть более сложным для реализации, чем другие категории приложений UWP. Рекомендуется проверить пример приложения рабочего процесса при чтении этого руководства, чтобы лучше понять, как можно реализовать различные функции. Некоторые функции, такие как различные проверки ошибок и управление пользовательским интерфейсом, отсутствуют в этом руководстве для простоты.

Начало работы

Приложение рабочего процесса должно указать точку входа в систему печати, чтобы ее можно было запустить в соответствующее время. Это делается путем вставки следующего объявления в элемент Application/Extensions файла проекта UWP package.appxmanifest.

<uap:Extension Category="windows.printWorkflowBackgroundTask"  
    EntryPoint="WFBackgroundTasks.WfBackgroundTask" />

Это важно

Существует множество сценариев, в которых настройка печати не требует ввода пользователем. По этой причине приложения рабочего процесса печати выполняются в качестве фоновых задач по умолчанию.

Если приложение рабочего процесса связано с исходным приложением, которое запустило задание печати (см. более поздний раздел инструкций по этому вопросу), система печати проверяет файлы манифеста для точки входа фоновой задачи.

Выполнить подготовительную работу над заказом на печать

Первое, что делает система печати с приложением рабочего процесса, — это активирует фоновую задачу (в этом случае класс WfBackgroundTask в пространстве имен WFBackgroundTasks). В методе Run фоновой задачи необходимо привести сведения о триггере задачи в качестве экземпляра PrintWorkflowTriggerDetails. Это обеспечит специальную функциональность для фоновой задачи рабочего процесса печати. Он предоставляет свойство PrintWorkflowSession, которое является экземпляром PrintWorkFlowBackgroundSession. Классы сеансов рабочего процесса печати — как фон, так и разновидности переднего плана — будут управлять последовательными шагами приложения рабочего процесса печати.

Затем зарегистрируйте методы обработчика для двух событий, которые будет вызывать этот класс сеанса. Эти методы будут определены позже.

public void Run(IBackgroundTaskInstance taskInstance) {
    // Take out a deferral here and complete once all the callbacks are done
    runDeferral = taskInstance.GetDeferral();

    // Associate a cancellation handler with the background task.
    taskInstance.Canceled += new BackgroundTaskCanceledEventHandler(OnCanceled);

    // cast the task's trigger details as PrintWorkflowTriggerDetails
    PrintWorkflowTriggerDetails workflowTriggerDetails = taskInstance.TriggerDetails as PrintWorkflowTriggerDetails;

    // Get the session manager, which is unique to this print job
    PrintWorkflowBackgroundSession sessionManager = workflowTriggerDetails.PrintWorkflowSession;

    // add the event handler callback routines
    sessionManager.SetupRequested += OnSetupRequested;
    sessionManager.Submitted += OnXpsOMPrintSubmitted;

    // Allow the event source to start
    // This call blocks until all of the workflow callbacks complete
    sessionManager.Start();
}

При вызове метода Start диспетчер сеансов сначала вызовет событие SetupRequested. Это событие предоставляет общие сведения о задаче печати и о задании на печать. На этом этапе билет на печать можно изменить в фоновом режиме.

private void OnSetupRequested(PrintWorkflowBackgroundSession sessionManager, PrintWorkflowBackgroundSetupRequestedEventArgs printTaskSetupArgs) {
    // Take out a deferral here and complete once all the callbacks are done
    Deferral setupRequestedDeferral = printTaskSetupArgs.GetDeferral();

    // Get general information about the source application, print job title, and session ID
    string sourceApplicationName = printTaskSetupArgs.Configuration.SourceAppDisplayName;
    string jobTitle = printTaskSetupArgs.Configuration.JobTitle;
    string sessionId = printTaskSetupArgs.Configuration.SessionId;

    // edit the print ticket
    WorkflowPrintTicket printTicket = printTaskSetupArgs.GetUserPrintTicketAsync();

    // ...

Важно отметить, что приложение определяет необходимость запуска компонента переднего плана именно в процессе обработки SetupRequested. Это может зависеть от параметра, ранее сохраненного в локальном хранилище, или события, произошедшие во время редактирования билета на печать, или это может быть статический параметр конкретного приложения.

// ...

if (UIrequested) {
    printTaskSetupArgs.SetRequiresUI();

    // Any data that is to be passed to the foreground task must be stored the app's local storage.
    // It should be prefixed with the sourceApplicationName string and the SessionId string, so that
    // it can be identified as pertaining to this workflow app session.
}

// Complete the deferral taken out at the start of OnSetupRequested
setupRequestedDeferral.Complete();

Выполнение переднего плана работы с заданием печати (необязательно)

Если был вызван метод SetRequiresUI, система печати изучит файл манифеста, чтобы определить точку входа в интерфейс основного приложения. Элемент Application/Extensions файла package.appxmanifest должен содержать следующие строки. Замените значение EntryPoint именем приложения переднего плана.

<uap:Extension Category="windows.printWorkflowForegroundTask"  
    EntryPoint="MyWorkFlowForegroundApp.App" />

Затем система печати вызывает метод OnActivated для заданной точки входа приложения. В методе OnActivated файла App.xaml.cs приложение рабочего процесса должно проверить тип активации, чтобы убедиться, что это активация рабочего процесса. В этом случае приложение рабочего процесса может преобразовать аргументы активации в объект PrintWorkflowUIActivatedEventArgs, который предоставляет объект PrintWorkflowForegroundSession в качестве свойства. Этот объект, как и его фоновый аналог в предыдущем разделе, содержит события, создаваемые системой печати, и вы можете назначить обработчики этим объектам. В этом случае функциональные возможности обработки событий будут реализованы в отдельном классе с именем WorkflowPage.

Во-первых, в файле App.xaml.cs:

protected override void OnActivated(IActivatedEventArgs args){

    if (args.Kind == ActivationKind.PrintWorkflowForegroundTask) {

        // the app should instantiate a new UI view so that it can properly handle the case when
        // several print jobs are active at the same time.
        Frame rootFrame = new Frame();
        if (null == Window.Current.Content)
        {
            rootFrame.Navigate(typeof(WorkflowPage));
            Window.Current.Content = rootFrame;
        }

        // Get the main page
        WorkflowPage workflowPage = (WorkflowPage)rootFrame.Content;

        // Make sure the page knows it's handling a foreground task activation
        workflowPage.LaunchType = WorkflowPage.WorkflowPageLaunchType.ForegroundTask;

        // Get the activation arguments
        PrintWorkflowUIActivatedEventArgs printTaskUIEventArgs = args as PrintWorkflowUIActivatedEventArgs;

        // Get the session manager
        PrintWorkflowForegroundSession taskSessionManager = printTaskUIEventArgs.PrintWorkflowSession;

        // Add the callback handlers - these methods are in the workflowPage class
        taskSessionManager.SetupRequested += workflowPage.OnSetupRequested;
        taskSessionManager.XpsDataAvailable += workflowPage.OnXpsDataAvailable;

        // start raising the print workflow events
        taskSessionManager.Start();
    }
}

Как только пользовательский интерфейс подключит обработчики событий и завершится метод OnActivated, система печати вызовет событие SetupRequested для обработки его пользовательским интерфейсом. Это событие предоставляет те же данные, что предоставляло событие настройки фоновой задачи, включая сведения о задании печати и документ о билете печати, но без возможности запросить запуск дополнительного пользовательского интерфейса. В файле WorkflowPage.xaml.cs:

internal void OnSetupRequested(PrintWorkflowForegroundSession sessionManager, PrintWorkflowForegroundSetupRequestedEventArgs printTaskSetupArgs) {
    // If anything asynchronous is going to be done, you need to take out a deferral here,
    // since otherwise the next callback happens once this one exits, which may be premature
    Deferral setupRequestedDeferral = printTaskSetupArgs.GetDeferral();

    // Get information about the source application, print job title, and session ID
    string sourceApplicationName = printTaskSetupArgs.Configuration.SourceAppDisplayName;
    string jobTitle = printTaskSetupArgs.Configuration.JobTitle;
    string sessionId = printTaskSetupArgs.Configuration.SessionId;
    // the following string should be used when storing data that pertains to this workflow session
    // (such as user input data that is meant to change the print content later on)
    string localStorageVariablePrefix = string.Format("{0}::{1}::", sourceApplicationName, sessionID);

    try
    {
        // receive and store user input
        // ...
    }
    catch (Exception ex)
    {
        string errorMessage = ex.Message;
        Debug.WriteLine(errorMessage);
    }
    finally
    {
        // Complete the deferral taken out at the start of OnSetupRequested
        setupRequestedDeferral.Complete();
    }
}

Затем система печати вызовет событие XpsDataAvailable для пользовательского интерфейса. В обработчике этого события приложение рабочего процесса может получить доступ ко всем данным, доступным для события установки, и может дополнительно считывать данные XPS напрямую как поток необработанных байтов, так и как объектную модель. Доступ к данным XPS позволяет пользовательскому интерфейсу предоставлять службы предварительной версии печати и предоставлять пользователю дополнительные сведения об операциях, выполняемых приложением рабочего процесса для данных.

В рамках этого обработчика событий приложение рабочего процесса должно получить объект отсрочки, если он продолжит взаимодействовать с пользователем. Без отсрочки система печати будет считать задачу пользовательского интерфейса завершенной, когда обработчик событий XpsDataAvailable завершится или когда будет вызван асинхронный метод. Когда приложение собрало все необходимые сведения из взаимодействия пользователя с пользовательским интерфейсом, оно должно завершить отсрочку, чтобы затем система печати двигалась вперед.

internal async void OnXpsDataAvailable(PrintWorkflowForegroundSession sessionManager, PrintWorkflowXpsDataAvailableEventArgs printTaskXpsAvailableEventArgs)
{
    // Take out a deferral
    Deferral xpsDataAvailableDeferral = printTaskXpsAvailableEventArgs.GetDeferral();

    SpoolStreamContent xpsStream = printTaskXpsAvailableEventArgs.Operation.XpsContent.GetSourceSpoolDataAsStreamContent();

    IInputStream inputStream = xpsStream.GetInputSpoolStream();

    using (var inputReader = new Windows.Storage.Streams.DataReader(inputStream))
    {
        // Read the XPS data from input stream
        byte[] xpsData = new byte[inputReader.UnconsumedBufferLength];
        while (inputReader.UnconsumedBufferLength > 0)
        {
            inputReader.ReadBytes(xpsData);
            // Do something with the XPS data, e.g. preview
            // ...
        }
    }

    // Complete the deferral taken out at the start of this method
    xpsDataAvailableDeferral.Complete();
}

Кроме того, экземпляр PrintWorkflowSubmittedOperation, предоставляемый аргументами события, предоставляет возможность отменить задание печати или указать, что задание выполнено успешно, но выходные задания печати не потребуются. Это достигается вызовом метода Complete со значением PrintWorkflowSubmittedStatus.

Замечание

Если приложение для управления рабочими процессами отменяет задание печати, настоятельно рекомендуется, чтобы оно предоставляло уведомление на экране о том, почему задание было отменено.

Завершите подготовительную работу над содержимым для печати.

После завершения отсрочки в пользовательском интерфейсе в событии PrintTaskXpsDataAvailable (или если шаг пользовательского интерфейса был обойден), система печати запустит событие Отправлено для фоновой задачи. В обработчике этого события приложение рабочего процесса может получить доступ ко всем одинаковым данным, предоставляемым событием XpsDataAvailable. Однако, в отличие от любого из предыдущих событий, Submitted также предоставляет доступ для записи к окончательному содержимому задания печати через экземпляр PrintWorkflowTarget.

Объект, используемый для спулинга данных для окончательной печати, зависит от того, получены исходные данные как необработанный поток байтов или как объектная модель XPS. Когда приложение рабочего процесса обращается к исходным данным через поток байтов, выходной байтовый поток предоставляется для записи окончательных данных задания. Когда приложение рабочего процесса обращается к исходным данным через объектную модель, средство записи документов предоставляется для записи объектов в выходное задание. В любом случае приложение рабочего процесса должно считывать все исходные данные, изменять все необходимые данные и записывать измененные данные в целевой объект вывода.

Когда фоновая задача завершит запись данных, она должна вызывать Complete на соответствующем объекте PrintWorkflowSubmittedOperation. После завершения этого шага в приложении и выхода обработчика событий отправленного, сеанс рабочего процесса закрывается, и пользователь может отслеживать статус окончательного задания печати с помощью стандартных диалоговых окон печати.

Заключительные шаги

Регистрация приложения для управления процессом печати на принтере

Ваше приложение для рабочего процесса связано с принтером, используя тот же тип отправки файлов метаданных, что и для WSD API. На самом деле одно приложение UWP может выступать как в качестве приложения рабочего процесса, так и WSDA, предоставляющего функциональные возможности параметров задачи печати. Выполните шаги , соответствующие WSDA, для создания сопоставления метаданных.

Разница заключается в том, что хотя WSDA автоматически активируются для пользователя (приложение всегда запускается при печати этого пользователя на связанном устройстве), приложения рабочих процессов не являются. У них есть отдельная политика, которая должна быть задана.

Настройка политики приложения рабочего процесса

Политика приложения рабочего процесса устанавливается командами PowerShell на устройстве, которое предназначено для запуска приложения рабочего процесса. Команды Set-Printer, Add-Printer (существующий порт) и Add-Printer (новый порт WSD) будут изменены, чтобы разрешить устанавливать политики рабочего процесса.

  • Disabled: приложения рабочего процесса не будут активированы.
  • Uninitialized: Приложения рабочего процесса будут активированы, если в системе установлен DCA для рабочего процесса. Если приложение не установлено, печать по-прежнему продолжится.
  • Enabled: Контракт на рабочий процесс будет активирован, если DCA рабочего процесса установлен в системе. Если приложение не установлено, печать завершится ошибкой.

Следующая команда делает приложение рабочего процесса обязательным на указанном принтере.

Set-Printer –Name "Microsoft XPS Document Writer" -WorkflowPolicy Enabled

Локальный пользователь может запустить эту политику на локальном принтере или для корпоративной реализации администратор принтера может запустить эту политику на сервере печати. Затем политика будет синхронизирована со всеми клиентскими подключениями. Администратор принтера может использовать эту политику всякий раз, когда добавляется новый принтер.

См. также

пример приложения рабочего процесса

пространства имен Windows.Graphics.Printing.Workflow