自訂列印工作流程Customize the print workflow

概觀Overview

開發人員可以使用列印工作流程應用程式,自訂列印工作流程體驗。Developers can customize the printing workflow experience through the use of a print workflow app. 列印工作流程應用程式是一種 UWP app,可擴充 Microsoft Store 裝置應用程式 (WSDA)的功能,所以在繼續進行之前,對 WSDA 有一定的了解會有幫助。Print workflow apps are UWP apps that expand on the functionality of Microsoft Store devices apps (WSDAs), so it will be helpful to have some familiarity with WSDAs before going further.

就像 WSDA 一樣,當來源應用程式的使用者選擇列印某些項目,並透過 [列印] 對話方塊瀏覽時,系統會檢查是否有關聯至該印表機的工作流程應用程式。Just as in the case of WSDAs, when the user of a source application elects to print something and navigates through the print dialog, the system checks whether a workflow app is associated with that printer. 如果有,列印工作流程應用程式便會啟動 (主要做為背景工作,以下會有更詳細說明)。If it is, the print workflow app launches (primarily as a background task; more on this below). 工作流程應用程式可以變更列印票證 (用於設定目前列印工作之印表機裝置設定的 XML 文件) 以及要列印的實際 XPS 內容。A workflow app is able to alter both the print ticket (the XML document that configures the printer device settings for the current print task) and the actual XPS content to be printed. 也可以選擇在程序中途啟動 UI,公開此功能給使用者。It can optionally expose this functionality to the user by launching a UI midway through the process. 完成工作之後,它會傳遞列印內容和列印票證給驅動程式。After doing its work, it passes the print content and print ticket on to the driver.

因為列印工作流程應用程式包含背景和前景元件,而且其功能可以搭配其他應用程式,因此實作上會比其他類型的 UWP 應用程式更為複雜。Because it involves background and foreground components, and because it is functionally coupled with other app(s), a print workflow app can be more complicated to implement than other categories of UWP apps. 建議您在閱讀本指南時一併查看工作流程應用程式範例,以便更加了解如何實作不同的功能。It is recommended that you inspect the Workflow app sample while reading this guide to better understand how the different features can be implemented. 為了簡化起見,本指南未包含某些功能,例如各種錯誤檢查和 UI 管理。Some features, such as various error checks and UI management, are absent from this guide for the sake of simplicity.

開始使用Getting started

工作流程應用程式必須向列印系統指出其進入點,以便可在適當時間將其啟動。The workflow app must indicate its entry point to the print system so that it can be launched at the appropriate time. 做法是在 UWP 專案 package.appxmanifest 檔案的 Application/Extensions 中的插入下列宣告。This is done by inserting the following declaration in the Application/Extensions element of the UWP project's package.appxmanifest file.

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

重要

在很多情況中,列印自訂不需要使用者輸入。There are many scenarios in which the print customization does not require user input. 基於這個原因,列印工作流程應用程式預設做為背景工作執行。For this reason, Print workflow apps run as background tasks by default.

如果工作流程應用程式關聯至啟動列印工作的來源應用程式工作 (有關這方面的指示,請參閱稍後章節),列印系統會檢查其資訊清單檔案中是否有背景工作進入點。If a workflow app is associated with the source application that started the print job (see later section for instructions on this), the print system examines its manifest files for a background task entry point.

在列印票證上執行背景工作Do background work on the print ticket

列印系統與工作流程應用程式合作的第一件事就是啟動其背景工作 (在本案例中是 WFBackgroundTasks 命名空間中的 WfBackgroundTask)。The first thing the print system does with the workflow app is activate its background task (In this case, the WfBackgroundTask class in the WFBackgroundTasks namespace). 在背景工作的 Run 方法中,您應將工作的觸發程序詳細資料傳送為 PrintWorkflowTriggerDetails 執行個體。In the background task's Run method, you should cast the task's trigger details as a PrintWorkflowTriggerDetails instance. 這可提供列印工作流程背景工作的特殊功能。This will provide the special functionality for a print workflow background task. 它會公開 PrintWorkflowSession 屬性,這是 PrintWorkFlowBackgroundSession 的執行個體。It exposes the PrintWorkflowSession property, which is an instance of PrintWorkFlowBackgroundSession. 列印工作流程工作階段類別 - 包括背景和前景種類 - 將會控制列印工作流程應用程式的連續步驟。Print workflow session classes - both the background and foreground varieties - will control the sequential steps of the print workflow app.

然後註冊此工作階段類別會引發之兩個事件的處理常式方法。Then register handler methods for the two events that this session class will raise. 您將在稍後定義這些方法。You will define these methods later on.

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 事件。When the Start method is called, the session manager will raise the SetupRequested event first. 這個事件會公開列印工作以及列印票證的一般資訊。This event exposes general information about the print task, as well as the print ticket. 在這個階段,可在背景中編輯列印票證。At this stage, the print ticket can be edited in the background.

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 的處理中,應用程式用來判斷是否啟動前景元件。Importantly, it is in the handling of the SetupRequested that the app will determine whether to launch a foreground component. 這可能取決於先前儲存到本機存放裝置的設定,或在編輯列印票證期間所發生的事件,或者可能是特定應用程式的靜態設定。This could depend on a setting that was previously saved to local storage, or an event that occurred during the editing of the print ticket, or it may be a static setting of your particular app.

// ...

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

在列印工作上執行前景工作 (選用)Do foreground work on the print job (optional)

如果呼叫 SetRequiresUI 方法,則列印系統會檢查資訊清單檔案是否有前景應用程式的進入點。If the SetRequiresUI method was called, then the print system will examine the manifest file for the entry point to the foreground application. package.appxmanifest 檔案的 Application/Extensions 項目必須具有下列行。The Application/Extensions element of your package.appxmanifest file must have the following lines. 以前景應用程式的名稱取代 EntryPoint 的值。Replace the value of EntryPoint with name of the foreground app.

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

接著,列印系統呼叫特定應用程式進入點的 OnActivated 方法。Next, the print system calls the OnActivated method for the given app entry point. App.xaml.cs 檔案的 OnActivated 方法中,工作流程應用程式應該會檢查啟用種類來確認是否為工作流程啟用。In the OnActivated method of its App.xaml.cs file, the workflow app should check the activation kind to verify that it is a workflow activation. 如果是,工作流程應用程式可以傳送啟用引數至 PrintWorkflowUIActivatedEventArgs 物件,此物件會將 PrintWorkflowForegroundSession 物件公開為屬性。If so, the workflow app can cast the activation arguments to a PrintWorkflowUIActivatedEventArgs object, which exposes a PrintWorkflowForegroundSession object as a property. 正如同上一節中的背景對等項目,此物件包含由列印系統引發的事件,您可以指定處理常式給這些事件。This object, like its background counterpart in the previous section, contains events that are raised by the print system, and you can assign handlers to these. 在此情況下,事件處理功能將在稱為 WorkflowPage 的不同類別中實作。In this case, the event-handling functionality will be implemented in a separate class called WorkflowPage.

首先,在 App.xaml.cs 檔案中:First, in the App.xaml.cs file:

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

UI 已連接事件處理常式且 OnActivated 方法已結束後,列印系統會引發 SetupRequested 事件讓 UI 來處理。Once the UI has attached event handlers and the OnActivated method has exited, the print system will fire the SetupRequested event for the UI to handle. 這個事件提供背景工作設定事件所提供的相同資料,包括列印工作資訊和列印票證文件,但不具有要求啟動額外 UI 的能力。This event provides the same data that the background task setup event provided, including the print job info and print ticket document, but without the ability to request the launch of additional UI. WorkflowPage.xaml.cs 檔案中:In the WorkflowPage.xaml.cs file:

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

接著,列印系統會引發 UI 的 XpsDataAvailable 事件。Next, the print system will raise the XpsDataAvailable event for the UI. 在此事件的處理常式中,工作流程應用程式可以存取設定事件可用的所有資料,並可以原始位元組串流或物件模型的形式另外直接讀取 XPS 資料。In the handler for this event, the workflow app can access all of the data available to the setup event and can additionally read the XPS data directly, either as a stream of raw bytes or as an object model. 存取 XPS 資料可讓 UI 提供預覽列印服務,以及提供工作流程應用程式將在資料上執行之作業的其他相關資訊給使用者。Access to the XPS data allows the UI to provide print preview services and to provide additional information to the user about the operations that the workflow app will execute on the data.

在這個事件處理常式中,如果工作流程應用程式將會繼續與使用者互動,則必須取得延遲物件。As part of this event handler, the workflow app must acquire a deferral object if it will continue to interact with the user. 如果沒有延遲,當 XpsDataAvailable 事件處理常式結束或呼叫非同步方法時,列印系統會將 UI 工作視為已完成。Without a deferral, the print system will consider the UI task complete when the XpsDataAvailable event handler exits or when it calls an async method. 當應用程式已從使用者與 UI 的互動收集到所需的所有資訊時,它應該完成延遲,讓列印系統可以前進。When the app has gathered all required information from the user's interaction with the UI, it should complete the deferral so that the print system can then advance.

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 執行個體提供選項來取消列印工作或指出工作成功但不需要輸出列印工作。Additionally, the PrintWorkflowSubmittedOperation instance exposed by the event args provides the option to cancel the print job or to indicate that the job is successful but that no output print job will be needed. 做法是呼叫 Complete 方法搭配 PrintWorkflowSubmittedStatus 值。This is done by calling the Complete method with a PrintWorkflowSubmittedStatus value.

注意

如果工作流程應用程式取消列印工作,強烈建議它提供快顯通知,指出為何取消工作。If the workflow app cancels the print job, it is highly recommended that it provide a toast notification indicating why the job was cancelled.

在列印內容上執行最終背景工作Do final background work on the print content

UI 完成 PrintTaskXpsDataAvailable 事件中的延遲延之後 (或如果略過 UI 步驟),列印系統會引發背景工作的 Submitted 事件。Once the UI has completed the deferral in the PrintTaskXpsDataAvailable event (or if the UI step was bypassed), the print system will fire the Submitted event for the background task. 在這個事件的處理常式中,工作流程應用程式可以存取 XpsDataAvailable 事件提供的所有相同資料。In the handler for this event, the workflow app can get access to all of the same data provided by the XpsDataAvailable event. 然而,與先前事件不同的是,Submitted 還透過 PrintWorkflowTarget 執行個體提供最終列印工作內容的寫入存取權。However, unlike any of the previous events, Submitted also provides write access to the final print job content through a PrintWorkflowTarget instance.

用來多工緩衝最終列印之資料的物件,取決於來源資料是以原始位元組串流還是 XPS 物件模型的形式來存取。The object that is used to spool the data for final printing depends on whether the source data is accessed as a raw byte stream or as the XPS object model. 當工作流程應用程式透過位元組串流存取來源資料,則會提供輸出位元組串流來寫入最終工作資料。When the workflow app accesses the source data through a byte stream, an output byte stream is provided to write the final job data to. 當工作流程應用程式透過物件模型存取來源資料,則會提供文件寫作程式來寫入物件至輸出工作。When the workflow app accesses the source data through the object model, a document writer is provided to write objects to the output job. 在任一種情況下,工作流程應用程式都應該會讀取所有資料來源、修改任何必要的資料,並將修改過的資料寫入輸出目標。In either case, the workflow app should read all of the source data, modify any data required, and write the modified data to the output target.

當背景工作完成寫入資料,它應該會在對應的 PrintWorkflowSubmittedOperation 物件上呼叫 CompleteWhen the background task finishes writing the data, it should call Complete on the corresponding PrintWorkflowSubmittedOperation object. 工作流程應用程式完成此步驟且 Submitted 事件處理常式結束後,工作流程工作階段會關閉,且使用者可以透過標準列印對話方塊監視最終列印工作的狀態。Once the workflow app completes this step and the Submitted event handler exits, the workflow session is closed and the user can monitor the status of the final print job through the standard print dialogs.

最後步驟Final steps

將列印工作流程應用程式註冊至印表機Register the print workflow app to the printer

使用和 WSDA 相同的中繼資料檔案提交類型,將您的工作流程應用程式關聯至印表機。Your workflow app is associated with a printer using the same type of metadata file submission as for WSDAs. 事實上,單一 UWP 應用程式可同時做為工作流程應用程式和提供工作列印設定功能的 WSDA。In fact, a single UWP application can act as both a workflow app and a WSDA that provides print task settings functionality. 請依照對應的建立中繼資料關聯的 WSDA 步驟來進行。Follow the corresponding WSDA steps for creating the metadata association.

不同之處在於,WSDA 會為使用者自動啟動 (當使用者在相關聯的裝置上列印時,應用程式一律會啟動),而工作流程應用程式不會。The difference is that while WSDAs are automatically activated for the user (the app will always launch when that user prints on the associated device), workflow apps are not. 必須為它們另外設定原則。They have a separate policy that must be set.

設定工作流程應用程式的原則Set the workflow app's policy

工作流程應用程式原則由 Powershell 命令在執行工作流程應用程式的裝置上設定。The workflow app policy is set by Powershell commands on the device that is to run the workflow app. 需修改 Set-Printer、Add-Printer (現有的連接埠) 和 Add-Printer (新的 WSD 連接埠) 命令以允許設定工作流程原則。The Set-Printer, Add-Printer (existing port) and Add-Printer (new WSD port) commands will be modified to allow Workflow policies to be set.

  • Disabled:不啟動工作流程應用程式。Disabled: Workflow apps will not be activated.
  • Uninitialized:如果系統中安裝工作流程 DCA,則會啟動工作流程應用程式。Uninitialized: Workflow apps will be activated if the Workflow DCA is installed in the system. 如果未安裝應用程式,列印仍會繼續。If the app is not installed, printing will still proceed.
  • Enabled:如果系統中安裝工作流程 DCA,則會啟動工作流程合約。Enabled: Workflow contract will be activated if the Workflow DCA is installed in the system. 如果未安裝應用程式,列印會失敗。If the app is not installed, printing will fail.

下列命令在指定的印表機上設定必要的工作流程應用程式。The following command makes the workflow app required on the specified printer.

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

本機使用者可以在本機印表機上執行這項原則,而對於企業實作,印表機系統管理員可以在列印伺服器上執行這項原則。A local user can run this policy on a local printer, or, for enterprise implementation, the printer administrator can run this policy on the Print Server. 接著原則會再同步至所有用戶端連線。The policy will then be synchronized to all client connections. 每當加入新的印表機,印表機系統管理員都可以使用這項原則。The printer admin can use this policy whenever a new printer is added.

另請參閱See also

工作流程應用程式範例Workflow app sample

Windows.Graphics.Printing.Workflow 命名空間Windows.Graphics.Printing.Workflow namespace