Anpassen des Druck-Workflows
Erstellen Sie benutzerdefinierte Druckworkflowfunktionen mithilfe einer Druckworkflow-App.
Übersicht
Druckworkflow-Apps sind UWP-Apps, die die Funktionalität von Microsoft Store-Geräte-Apps (WSDAs) erweitern, daher ist es hilfreich, sich mit WSDAs vertraut zu machen, bevor Sie fortfahren.
Genau wie bei WSDAs überprüft das System, ob der Benutzer einer Quellanwendung etwas druckt und durch das Druckdialogfeld navigiert, ob eine Workflow-App diesem Drucker zugeordnet ist. Wenn dies der Fall ist, wird die Druckworkflow-App gestartet (in erster Linie als Hintergrundaufgabe; mehr dazu unten). Eine Workflow-App kann sowohl das Druckticket (das XML-Dokument, das die Druckergeräteeinstellungen für die aktuelle Druckaufgabe konfiguriert) als auch den tatsächlichen XPS-Inhalt ändern, der gedruckt werden soll. Sie kann diese Funktionalität optional für den Benutzer verfügbar machen, indem eine Benutzeroberfläche mitten im Prozess gestartet wird. Nachdem sie ihre Arbeit ausgeführt hat, übergibt sie den Druckinhalt und das Druckticket an den Fahrer.
Da es Sich um Hintergrund- und Vordergrundkomponenten handelt und sie funktionell mit anderen Apps gekoppelt ist, kann eine Druckworkflow-App komplizierter implementiert werden als andere Kategorien von UWP-Apps. Es wird empfohlen, das Beispiel für die Workflow-App beim Lesen dieses Leitfadens zu überprüfen, um besser zu verstehen, wie die verschiedenen Features implementiert werden können. Einige Features, wie z. B. verschiedene Fehlerüberprüfungen und die Benutzeroberflächenverwaltung, fehlen aus diesem Leitfaden aus Gründen der Einfachheit.
Erste Schritte
Die Workflow-App muss ihren Einstiegspunkt in das Drucksystem angeben, damit sie zur entsprechenden Zeit gestartet werden kann. Dazu fügen Sie die folgende Deklaration in das Application/Extensions
Element der Datei "package.appxmanifest" des UWP-Projekts ein.
<uap:Extension Category="windows.printWorkflowBackgroundTask"
EntryPoint="WFBackgroundTasks.WfBackgroundTask" />
Wichtig
Es gibt viele Szenarien, in denen die Druckanpassung keine Benutzereingaben erfordert. Aus diesem Grund werden Druckworkflow-Apps standardmäßig als Hintergrundaufgaben ausgeführt.
Wenn eine Workflow-App der Quellanwendung zugeordnet ist, die den Druckauftrag gestartet hat (weitere Anweisungen hierzu finden Sie im späteren Abschnitt), überprüft das Drucksystem seine Manifestdateien auf einen Einstiegspunkt für Hintergrundaufgaben.
Ausführen von Hintergrundarbeiten für das Druckticket
Das erste, was das Drucksystem mit der Workflow-App ausführt, ist die Aktivierung der Hintergrundaufgabe (in diesem Fall die WfBackgroundTask
Klasse im WFBackgroundTasks
Namespace). In der Methode der Hintergrundaufgabe Run
sollten Sie die Triggerdetails der Aufgabe als PrintWorkflowTriggerDetails-Instanz umwandeln. Dadurch wird die spezielle Funktionalität für eine Hintergrundaufgabe für Druckworkflows bereitgestellt. Sie macht die PrintWorkflowSession-Eigenschaft verfügbar, bei der es sich um eine Instanz von PrintWorkFlowBackgroundSession handelt. Druckworkflowsitzungsklassen – sowohl die Hintergrund- als auch die Vordergrundvariablen – steuern die sequenziellen Schritte der Druckworkflow-App.
Registrieren Sie dann Handlermethoden für die beiden Ereignisse, die diese Sitzungsklasse auslöst. Sie definieren diese Methoden später.
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();
}
Wenn die Start
Methode aufgerufen wird, löst der Sitzungs-Manager zuerst das SetupRequested-Ereignis aus. Dieses Ereignis macht allgemeine Informationen über die Druckaufgabe sowie das Druckticket verfügbar. In dieser Phase kann das Druckticket im Hintergrund bearbeitet werden.
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();
// ...
Wichtig ist, dass die App bei der Behandlung von SetupRequested bestimmt, ob eine Vordergrundkomponente gestartet werden soll. Dies kann von einer Einstellung abhängen, die zuvor im lokalen Speicher gespeichert wurde, oder von einem Ereignis, das während der Bearbeitung des Drucktickets aufgetreten ist, oder es kann sich um eine statische Einstellung Ihrer jeweiligen App handeln.
// ...
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();
Ausführen von Vordergrundarbeiten am Druckauftrag (optional)
Wenn die SetRequiresUI-Methode aufgerufen wurde, überprüft das Drucksystem die Manifestdatei für den Einstiegspunkt in die Vordergrundanwendung. Das Application/Extensions
Element der Datei "package.appxmanifest " muss die folgenden Zeilen enthalten. Ersetzen Sie den Wert der EntryPoint
Vordergrund-App durch den Namen der Vordergrund-App.
<uap:Extension Category="windows.printWorkflowForegroundTask"
EntryPoint="MyWorkFlowForegroundApp.App" />
Als Nächstes ruft das Drucksystem die OnActivated-Methode für den angegebenen App-Einstiegspunkt auf. In der OnActivated-Methode der App.xaml.cs-Datei sollte die Workflow-App die Aktivierungsart überprüfen, um zu überprüfen, ob es sich um eine Workflowaktivierung handelt. Wenn ja, kann die Workflow-App die Aktivierungsargumente in ein PrintWorkflowUIActivatedEventArgs -Objekt umwandeln, das ein PrintWorkflowForegroundSession -Objekt als Eigenschaft verfügbar macht. Dieses Objekt enthält wie sein Hintergrundentsprechung im vorherigen Abschnitt Ereignisse, die vom Drucksystem ausgelöst werden, und Sie können diesen Handler zuweisen. In diesem Fall wird die Ereignisbehandlungsfunktion in einer separaten Klasse implementiert, die aufgerufen WorkflowPage
wird.
Zuerst in der datei 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();
}
}
Sobald die Benutzeroberfläche Ereignishandler angefügt hat und die OnActivated-Methode beendet wurde, löst das Drucksystem das SetupRequested-Ereignis aus, damit die Benutzeroberfläche verarbeitet werden kann. Dieses Ereignis enthält dieselben Daten wie das bereitgestellte Ereignis für die Einrichtung von Hintergrundaufgaben, einschließlich der Druckauftragsinformationen und des Druckticketdokuments, aber ohne die Möglichkeit, den Start einer zusätzlichen Benutzeroberfläche anzufordern. In der datei 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();
}
}
Als Nächstes löst das Drucksystem das XpsDataAvailable-Ereignis für die Benutzeroberfläche aus. Im Handler für dieses Ereignis kann die Workflow-App auf alle für das Setupereignis verfügbaren Daten zugreifen und die XPS-Daten zusätzlich direkt als Datenstrom von unformatierten Bytes oder als Objektmodell lesen. Der Zugriff auf die XPS-Daten ermöglicht es der Benutzeroberfläche, Druckvorschaudienste bereitzustellen und dem Benutzer zusätzliche Informationen zu den Vorgängen bereitzustellen, die von der Workflow-App für die Daten ausgeführt werden.
Im Rahmen dieses Ereignishandlers muss die Workflow-App ein Verzögerungsobjekt abrufen, wenn sie weiterhin mit dem Benutzer interagieren wird. Ohne Verzögerung berücksichtigt das Drucksystem den Abschluss der UI-Aufgabe, wenn der XpsDataAvailable-Ereignishandler beendet wird oder wenn eine asynchrone Methode aufgerufen wird. Wenn die App alle erforderlichen Informationen aus der Interaktion des Benutzers mit der Benutzeroberfläche gesammelt hat, sollte die Verzögerung abgeschlossen werden, damit das Drucksystem dann voranschreiten kann.
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();
}
Darüber hinaus bietet die PrintWorkflowSubmittedOperation-Instanz , die von den Ereignisargumenten verfügbar gemacht wird, die Option, den Druckauftrag abzubrechen oder anzugeben, dass der Auftrag erfolgreich ist, aber kein Ausgabedruckauftrag erforderlich ist. Dazu rufen Sie die Complete-Methode mit einem PrintWorkflowSubmittedStatus-Wert auf.
Hinweis
Wenn die Workflow-App den Druckauftrag abbricht, wird dringend empfohlen, eine Popupbenachrichtigung bereitzustellen, die angibt, warum der Auftrag abgebrochen wurde.
Ausführen der endgültigen Hintergrundarbeit für den Druckinhalt
Sobald die Benutzeroberfläche die Verzögerung im PrintTaskXpsDataAvailable-Ereignis abgeschlossen hat (oder wenn der UI-Schritt umgangen wurde), löst das Drucksystem das übermittelte Ereignis für die Hintergrundaufgabe aus. Im Handler für dieses Ereignis kann die Workflow-App Zugriff auf alle vom XpsDataAvailable-Ereignis bereitgestellten Daten erhalten. Im Gegensatz zu den vorherigen Ereignissen bietet Submitted jedoch auch Schreibzugriff auf den endgültigen Druckauftragsinhalt über eine PrintWorkflowTarget-Instanz.
Das Objekt, das zum Spoolen der Daten für den endgültigen Druck verwendet wird, hängt davon ab, ob auf die Quelldaten als unformatierter Bytedatenstrom oder als XPS-Objektmodell zugegriffen wird. Wenn die Workflow-App über einen Bytedatenstrom auf die Quelldaten zugreift, wird ein Ausgabebytestream bereitgestellt, in den die endgültigen Auftragsdaten geschrieben werden. Wenn die Workflow-App über das Objektmodell auf die Quelldaten zugreift, wird ein Dokumentschreiber bereitgestellt, um Objekte in den Ausgabeauftrag zu schreiben. In beiden Fällen sollte die Workflow-App alle Quelldaten lesen, alle erforderlichen Daten ändern und die geänderten Daten in das Ausgabeziel schreiben.
Wenn die Hintergrundaufgabe das Schreiben der Daten abgeschlossen hat, sollte "Complete" für das entsprechende PrintWorkflowSubmittedOperation -Objekt aufgerufen werden. Sobald die Workflow-App diesen Schritt abgeschlossen hat und der Übermittelte Ereignishandler beendet wird, wird die Workflowsitzung geschlossen, und der Benutzer kann den Status des endgültigen Druckauftrags über die Standarddruckdialoge überwachen.
Abschließende Schritte
Registrieren der Druckworkflow-App für den Drucker
Ihre Workflow-App ist einem Drucker zugeordnet, der dieselbe Art von Metadatendateiübermittlung wie für WSDAs verwendet. Tatsächlich kann eine einzelne UWP-Anwendung sowohl als Workflow-App als auch als WSDA fungieren, die Druckaufgabeneinstellungen bereitstellt. Führen Sie die entsprechenden WSDA-Schritte zum Erstellen der Metadatenzuordnung aus.
Der Unterschied besteht darin, dass während WSDAs automatisch für den Benutzer aktiviert werden (die App wird immer gestartet, wenn dieser Benutzer auf dem zugeordneten Gerät druckt), workflow-Apps nicht. Sie verfügen über eine separate Richtlinie, die festgelegt werden muss.
Festlegen der Richtlinie der Workflow-App
Die Workflow-App-Richtlinie wird von PowerShell-Befehlen auf dem Gerät festgelegt, auf dem die Workflow-App ausgeführt werden soll. Die Befehle "Set-Printer", "Add-Printer" (vorhandener Port) und "Add-Printer" (neuer WSD-Port) werden so geändert, dass Workflowrichtlinien festgelegt werden können.
Disabled
: Workflow-Apps werden nicht aktiviert.Uninitialized
: Workflow-Apps werden aktiviert, wenn der Workflow-DCA im System installiert ist. Wenn die App nicht installiert ist, wird der Druckvorgang weiterhin fortgesetzt.Enabled
: Workflow-Vertrag wird aktiviert, wenn der Workflow-DCA im System installiert ist. Wenn die App nicht installiert ist, schlägt das Drucken fehl.
Mit dem folgenden Befehl wird die Workflow-App auf dem angegebenen Drucker benötigt.
Set-Printer –Name "Microsoft XPS Document Writer" -WorkflowPolicy Enabled
Ein lokaler Benutzer kann diese Richtlinie auf einem lokalen Drucker ausführen, oder für die Unternehmensimplementierung kann der Druckeradministrator diese Richtlinie auf dem Druckserver ausführen. Die Richtlinie wird dann mit allen Clientverbindungen synchronisiert. Der Druckeradministrator kann diese Richtlinie immer dann verwenden, wenn ein neuer Drucker hinzugefügt wird.