Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Crie experiências personalizadas de fluxo de trabalho de impressão por meio do uso de um aplicativo de fluxo de trabalho de impressão.
Visão geral
Aplicativos de fluxo de trabalho de impressão são aplicativos UWP que expandem a funcionalidade de de aplicativos de dispositivos da Microsoft Store (WSDAs), portanto, será útil ter alguma familiaridade com os WSDAs antes de ir mais longe.
Assim como no caso de 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 de impressora para a tarefa de impressão atual) e o conteúdo XPS real a ser impresso. Opcionalmente, pode expor essa funcionalidade ao usuário, abrindo uma interface 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, como está 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 de aplicativo de fluxo de trabalho ao ler 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 para fins de simplicidade.
Como começar
O aplicativo de fluxo de trabalho deve indicar seu ponto de entrada para o sistema de impressão para que ele possa ser iniciado no momento apropriado. Isso é feito inserindo a declaração a seguir no elemento
<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.
Realizar a tarefa em segundo plano para o 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 classe WfBackgroundTask
no namespace WFBackgroundTasks
). No método Run
da tarefa em segundo plano, você deve converter os detalhes do gatilho da tarefa como uma instância PrintWorkflowTriggerDetails. Isso irá oferecer uma funcionalidade especial para uma tarefa em segundo plano no fluxo de trabalho de impressão. Ele expõe a propriedade PrintWorkflowSession, que é uma instância de PrintWorkFlowBackgroundSession. As classes de sessão do fluxo de trabalho de impressão – tanto as de plano de fundo quanto as de primeiro plano – coordenarão as etapas sequenciais do app de fluxo de trabalho de impressão.
Em seguida, registre métodos de manipulador para os dois eventos que essa classe de sessão gerará. Você definirá esses métodos posteriormente.
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 método Start
é chamado, o gerenciador de sessão acionará o evento SetupRequested primeiro. Esse evento expõe informações gerais sobre a tarefa de impressão, assim como o tíquete de impressão. Neste estágio, 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 destacar que é na manipulação do SetupRequested que o aplicativo determinará se irá iniciar um componente em primeiro plano. 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 o trabalho em primeiro plano para a impressão (opcional)
Se o método SetRequiresUI foi chamado, o sistema de impressão examinará o arquivo de manifesto para o ponto de entrada do aplicativo de primeiro plano. O elemento 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 especificado. 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 seu equivalente em segundo plano na seção anterior, contém eventos gerados pelo sistema de impressão e você pode atribuir manipuladores a eles. Nesse caso, a funcionalidade de tratamento 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 manipuladores de eventos anexados 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 fornecidos pelo evento de configuração da tarefa em segundo plano, incluindo as informações do trabalho de impressão e o documento do tíquete de impressão, mas sem a capacidade de solicitar o início de uma interface de 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 também pode ler os dados XPS diretamente, seja 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 deverá adquirir um objeto de adiamento se ele continuar a interagir com o usuário. Sem um adiamento, o sistema de impressão considerará a tarefa de interface do usuário concluída quando o manipulador de eventos XpsDataAvailable for encerrado ou quando ele 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 em forma de 'toast' indicando por que o trabalho foi cancelado.
Finalizar o trabalho de bastidores 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,
O objeto usado para fazer o spool dos dados para impressão final depende se os dados de origem são acessados como um fluxo bruto de bytes 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, é fornecido um fluxo de bytes de saída para gravar os dados finais do trabalho. Quando o aplicativo de fluxo de trabalho acessa os dados de origem por meio do modelo de objeto, um gravador de documentos é 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 Concluir no objeto PrintWorkflowSubmittedOperation correspondente. Depois que o aplicativo de fluxo de trabalho concluir esta etapa e o manipulador de eventos Submetido 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
Registrar 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 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, enquanto os WSDAs são ativados automaticamente para o usuário (o app sempre será iniciado quando o usuário imprimir no dispositivo associado), os apps de workflow 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 de aplicativo de fluxo de trabalho é definida pelos 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 a DCA do fluxo de trabalho estiver instalada no sistema. Se o aplicativo não estiver instalado, a impressão continuará. -
Enabled
: o contrato de fluxo de trabalho será ativado se a DCA do fluxo de trabalho estiver instalada 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 empresarial, o administrador da impressora pode executar essa política no Servidor de Impressão. Em seguida, a política será sincronizada com todas as conexões de cliente. O administrador da impressora pode usar essa política sempre que uma nova impressora é adicionada.