Personalizar o fluxo de trabalho de impressão
Crie experiências de fluxo de trabalho de impressão personalizadas por meio do uso de um aplicativo de fluxo de trabalho de impressão.
Visão geral
Os aplicativos de fluxo de trabalho de impressão são aplicativos UWP que expandem a funcionalidade dos aplicativos de dispositivos da Microsoft Store (WSDAs), portanto, será útil ter alguma familiaridade com os WSDAs antes de prosseguir.
Assim como no caso dos WSDAs, quando o usuário de um aplicativo de origem opta por imprimir algo e navega pela caixa de diálogo de impressão, o sistema verifica se um aplicativo de fluxo de trabalho está associado a essa impressora. Se estiver, o aplicativo de fluxo de trabalho de impressão será iniciado (principalmente como uma tarefa em segundo plano; mais sobre isso abaixo). Um aplicativo de fluxo de trabalho é capaz de alterar o tíquete de impressão (o documento XML que define as configurações do dispositivo da impressora para a tarefa de impressão atual) e o conteúdo XPS real a ser impresso. Opcionalmente, ele pode expor essa funcionalidade ao usuário iniciando uma interface do usuário no meio do processo. Depois de fazer seu trabalho, ele passa o conteúdo de impressão e o tíquete de impressão para o driver.
Como envolve componentes em segundo plano e em primeiro plano e porque é funcionalmente acoplado a outros aplicativos, um aplicativo de fluxo de trabalho de impressão pode ser mais complicado de implementar do que outras categorias de aplicativos UWP. É recomendável que você inspecione o exemplo do aplicativo Workflow enquanto lê este guia para entender melhor como os diferentes recursos podem ser implementados. Alguns recursos, como várias verificações de erros e gerenciamento de interface do usuário, estão ausentes deste guia por uma questão de simplicidade.
Introdução
O aplicativo de fluxo de trabalho deve indicar seu ponto de entrada para o sistema de impressão para que possa ser iniciado no momento apropriado. Isso é feito inserindo a declaração a seguir no Application/Extensions
elemento do arquivo package.appxmanifest do projeto UWP.
<uap:Extension Category="windows.printWorkflowBackgroundTask"
EntryPoint="WFBackgroundTasks.WfBackgroundTask" />
Importante
Há muitos cenários em que a personalização de impressão não requer entrada do usuário. Por esse motivo, os aplicativos de fluxo de trabalho de impressão são executados como tarefas em segundo plano por padrão.
Se um aplicativo de fluxo de trabalho estiver associado ao aplicativo de origem que iniciou o trabalho de impressão (consulte a seção posterior para obter instruções sobre isso), o sistema de impressão examinará seus arquivos de manifesto para um ponto de entrada de tarefa em segundo plano.
Faça o trabalho em segundo plano no tíquete de impressão
A primeira coisa que o sistema de impressão faz com o aplicativo de fluxo de trabalho é ativar sua tarefa em segundo plano (nesse caso, a WfBackgroundTask
classe no WFBackgroundTasks
namespace). No método da tarefa em Run
segundo plano, você deve converter os detalhes do gatilho da tarefa como uma instância PrintWorkflowTriggerDetails . Isso fornecerá a funcionalidade especial para uma tarefa em segundo plano do fluxo de trabalho de impressão. Ele expõe a propriedade PrintWorkflowSession, que é uma instância de PrintWorkFlowBackgroundSession. As classes de sessão de fluxo de trabalho de impressão - as variedades de plano de fundo e primeiro plano - controlarão as etapas sequenciais do aplicativo de fluxo de trabalho de impressão.
Em seguida, registre os métodos do manipulador para os dois eventos que essa classe de sessão gerará. Você definirá esses métodos mais tarde.
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();
}
Quando o Start
método for chamado, o gerenciador de sessão gerará o evento SetupRequested primeiro. Esse evento expõe informações gerais sobre a tarefa de impressão, bem como o tíquete de impressão. Nesta fase, o tíquete de impressão pode ser editado em segundo plano.
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();
// ...
É importante ressaltar que é no tratamento do SetupRequested que o aplicativo determinará se um componente em primeiro plano deve ser iniciado. Isso pode depender de uma configuração que foi salva anteriormente no armazenamento local ou de um evento que ocorreu durante a edição do tíquete de impressão, ou pode ser uma configuração estática do seu aplicativo específico.
// ...
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();
Fazer trabalho em primeiro plano no trabalho de impressão (opcional)
Se o método SetRequiresUI tiver sido chamado, o sistema de impressão examinará o arquivo de manifesto para o ponto de entrada para o aplicativo em primeiro plano. O Application/Extensions
elemento do arquivo package.appxmanifest deve ter as linhas a seguir. Substitua o valor de EntryPoint
pelo nome do aplicativo em primeiro plano.
<uap:Extension Category="windows.printWorkflowForegroundTask"
EntryPoint="MyWorkFlowForegroundApp.App" />
Em seguida, o sistema de impressão chama o método OnActivated para o ponto de entrada do aplicativo fornecido. No método OnActivated de seu arquivo App.xaml.cs, o aplicativo de fluxo de trabalho deve verificar o tipo de ativação para verificar se é uma ativação de fluxo de trabalho. Nesse caso, o aplicativo de fluxo de trabalho pode converter os argumentos de ativação em um objeto PrintWorkflowUIActivatedEventArgs , que expõe um objeto PrintWorkflowForegroundSession como uma propriedade. Esse objeto, como sua contraparte em segundo plano na seção anterior, contém eventos que são gerados pelo sistema de impressão e você pode atribuir manipuladores a eles. Nesse caso, a funcionalidade de manipulação de eventos será implementada em uma classe separada chamada WorkflowPage
.
Primeiro, no arquivo 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();
}
}
Depois que a interface do usuário tiver anexado manipuladores de eventos e o método OnActivated for encerrado, o sistema de impressão disparará o evento SetupRequested para a interface do usuário manipular. Esse evento fornece os mesmos dados que o evento de configuração de tarefa em segundo plano forneceu, incluindo as informações do trabalho de impressão e o documento de tíquete de impressão, mas sem a capacidade de solicitar a inicialização de uma interface do usuário adicional. No arquivo 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();
}
}
Em seguida, o sistema de impressão gerará o evento XpsDataAvailable para a interface do usuário. No manipulador desse evento, o aplicativo de fluxo de trabalho pode acessar todos os dados disponíveis para o evento de instalação e, além disso, pode ler os dados XPS diretamente, como um fluxo de bytes brutos ou como um modelo de objeto. O acesso aos dados XPS permite que a interface do usuário forneça serviços de visualização de impressão e forneça informações adicionais ao usuário sobre as operações que o aplicativo de fluxo de trabalho executará nos dados.
Como parte desse manipulador de eventos, o aplicativo de fluxo de trabalho deve adquirir um objeto de adiamento se continuar a interagir com o usuário. Sem um adiamento, o sistema de impressão considerará a tarefa da interface do usuário concluída quando o manipulador de eventos XpsDataAvailable for encerrado ou quando chamar um método assíncrono. Quando o aplicativo tiver coletado todas as informações necessárias da interação do usuário com a interface do usuário, ele deverá concluir o adiamento para que o sistema de impressão possa avançar.
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();
}
Além disso, a instância PrintWorkflowSubmittedOperation exposta pelos argumentos de evento fornece a opção de cancelar o trabalho de impressão ou indicar que o trabalho foi bem-sucedido, mas que nenhum trabalho de impressão de saída será necessário. Isso é feito chamando o método Complete com um valor PrintWorkflowSubmittedStatus.
Observação
Se o aplicativo de fluxo de trabalho cancelar o trabalho de impressão, é altamente recomendável que ele forneça uma notificação do sistema indicando por que o trabalho foi cancelado.
Faça o trabalho final de fundo no conteúdo impresso
Depois que a interface do usuário tiver concluído o adiamento no evento PrintTaskXpsDataAvailable (ou se a etapa da interface do usuário tiver sido ignorada), o sistema de impressão disparará o evento Submitted para a tarefa em segundo plano. No manipulador desse evento, o aplicativo de fluxo de trabalho pode obter acesso a todos os mesmos dados fornecidos pelo evento XpsDataAvailable . No entanto, ao contrário de qualquer um dos eventos anteriores, Submitted também fornece acesso de gravação ao conteúdo do trabalho de impressão final por meio de uma instância PrintWorkflowTarget.
O objeto usado para colocar os dados em spool para impressão final depende se os dados de origem são acessados como um fluxo de bytes brutos ou como o modelo de objeto XPS. Quando o aplicativo de fluxo de trabalho acessa os dados de origem por meio de um fluxo de bytes, um fluxo de bytes de saída é fornecido para gravar os dados do trabalho final. Quando o aplicativo de fluxo de trabalho acessa os dados de origem por meio do modelo de objeto, um gravador de documento é fornecido para gravar objetos no trabalho de saída. Em ambos os casos, o aplicativo de fluxo de trabalho deve ler todos os dados de origem, modificar todos os dados necessários e gravar os dados modificados no destino de saída.
Quando a tarefa em segundo plano terminar de gravar os dados, ela deverá chamar Complete no objeto PrintWorkflowSubmittedOperation correspondente. Depois que o aplicativo de fluxo de trabalho concluir essa etapa e o manipulador de eventos Enviado for encerrado, a sessão de fluxo de trabalho será fechada e o usuário poderá monitorar o status do trabalho de impressão final por meio das caixas de diálogo de impressão padrão.
Etapas finais
Registre o aplicativo de fluxo de trabalho de impressão na impressora
Seu aplicativo de fluxo de trabalho está associado a uma impressora usando o mesmo tipo de envio de arquivo de metadados que para WSDAs. Na verdade, um único aplicativo UWP pode atuar como um aplicativo de fluxo de trabalho e um WSDA que fornece a funcionalidade de configurações de tarefa de impressão. Siga as etapas WSDA correspondentes para criar a associação de metadados.
A diferença é que, embora os WSDAs sejam ativados automaticamente para o usuário (o aplicativo sempre será iniciado quando o usuário imprimir no dispositivo associado), os aplicativos de fluxo de trabalho não são. Eles têm uma política separada que deve ser definida.
Definir a política do aplicativo de fluxo de trabalho
A política do aplicativo de fluxo de trabalho é definida por comandos do Powershell no dispositivo que deve executar o aplicativo de fluxo de trabalho. Os comandos Set-Printer, Add-Printer (porta existente) e Add-Printer (nova porta WSD) serão modificados para permitir que as políticas de fluxo de trabalho sejam definidas.
Disabled
: Os aplicativos de fluxo de trabalho não serão ativados.Uninitialized
: Os aplicativos de fluxo de trabalho serão ativados se o DCA de fluxo de trabalho estiver instalado no sistema. Se o aplicativo não estiver instalado, a impressão continuará.Enabled
: O contrato de fluxo de trabalho será ativado se o DCA de fluxo de trabalho estiver instalado no sistema. Se o aplicativo não estiver instalado, a impressão falhará.
O comando a seguir torna o aplicativo de fluxo de trabalho necessário na impressora especificada.
Set-Printer –Name "Microsoft XPS Document Writer" -WorkflowPolicy Enabled
Um usuário local pode executar essa política em uma impressora local ou, para implementação corporativa, o administrador da impressora pode executar essa política no Servidor de Impressão. A política será sincronizada com todas as conexões do cliente. O administrador da impressora pode usar essa política sempre que uma nova impressora for adicionada.