Blog > Juli 2010
Im siebten Teil der Workflow Serie schreiben wir den Code für unseren Workflow.
Veröffentlicht am 31.07.2010 22:41:04 von Reiner Ganser mit 3 Kommentar(en)
Beginnen wir mit dem Code nach dem Start des Workflows: Doppelklick auf eventDrivenActivity1 und wir landen in deren Innereien: Wir klicken auf die Activity onWorkflowActivated1, um diese auszuwählen. In den Eigenschaften dieser Activity existiert die Eigenschaft Invoked, welche momentan noch leer ist. Man kann hier nun eine Methode eintragen und beim Drücken der Eingabetaste, wird der Code angelegt und man landet auch direkt in diesem. Wir verwenden die Methode OnWorkflowActivated: Im Code angelangt, brauchen wir noch ein paar variablen, die wir im Workflow benutzen wollen und definieren diese zuerst: #region Variables
private string _reviewerID = ""; // Login Name des Reviewers private string _approverID = ""; // Login Name des Genehmigers private string _instructions = ""; // Anweisungen für den Genehmiger private string _status = ""; // Enthält den Status der jeweiligen Aufgabe private string _comment = ""; // Kommentare, die im Aufgaben Formular angegeben werden können
#endregion
Innerhalb der Methode OnWorkflowActivated() können wir jetzt die Daten, die der Benutzer im Startformular eingegeben hat abholen, auspacken und den Variablen zuweisen: private void OnWorkflowActivated(object sender, ExternalDataEventArgs e) { try { XmlDocument retData = new XmlDocument(); retData.LoadXml(workflowProperties.InitiationData); XmlNode approverNode = retData.SelectSingleNode("//approver"); if (null != approverNode) { _approverID = approverNode.InnerText; } XmlNode instructionNode = retData.SelectSingleNode("//instructions"); if (null != instructionNode) { _instructions = instructionNode.InnerText; } } catch (Exception ex) { } }
Als nächstes gehen wir zurück in den Workflow Designer und dort zurück auf die Workflow Übersicht. Im Zustand stateApprover können wir einen Doppelklick auf die Activity stateInit_Approver machen. Für die enthaltene Activity createTask_Approver brauchen wir nun ebenfalls wieder einen Event Handler, der es uns ermöglicht, die Aufgabe für den Genehmiger zu initialisieren. Die Methode, die aufgerufen werden soll nenne ich OnTaskCreate_Approver: Innerhalb der angelegten Methode initialisieren wird die Aufgabe für den Genehmiger mit einer neuen TaskId (GUID), sowie den sonstigen Parametern für die Aufgabe (an wen zuweisen, Titel, Beschreibung). Zusätzlich geben wir hier an, welches Formular verwendet werden soll: private void onTaskCreate_Approver(object sender, EventArgs e) { try { TaskId_Approver = Guid.NewGuid(); TaskProperties_Approver.Title = "Bitte Dokument genehmigen."; TaskProperties_Approver.AssignedTo = _approverID; TaskProperties_Approver.Description = _instructions; TaskProperties_Approver.TaskType = 0; // Nr. Des Aufgaben Formulars TaskProperties_Approver.ExtendedProperties["instructions"] = _instructions; } catch (Exception ex) { } }
In obigem Code findet man die Anweisung TaskProperties_Approver.TaskType = 0; Diese weist das Formular mit der ID 0 unserer Aufgabe für den Genehmiger zu. Im vorigen Post haben wir ja in der Datei elements.xml die ID der InfoPath Formulare in den Elementen <Task0_FormURN> und <Task1_FormURN> eingetragen. Die obige Codezeile bedeutet in unserem Falkl nichts anderes als dass das Formular im Element <Task0_FormURN> verwendet wird. In gleicher Weise werden wir später für den Reviewer die ID 1 verwenden und somit auf die InfoPath Formular ID verweisen, die im Element <Task1_FormURN> hinterlegt ist. In obigem Code ist zusätzlich die Anweisung TaskProperties_Approver.ExtendedProperties["instructions"] = _instructions;
zu finden. Diese übergibt die Anweisungen (_instructions) an das Feld instructions im InfoPath Formular. Wir haben ja dafür anhand der Datei ItemMetadata.XML eine 2. Datenquelle erstellt, die die Daten lesen kann und ins entsprechende Feld des Formulars schreibt.
Damit haben ist die Aufgabe für den Gewnehmiger angelegt. Jetzt müssen wir den Code implementieren, der die Aktionen im Aufgabenformular auswertet, also ob der Genehmiger genehmigt oder abgelehnt hat. Dazu müssen wir diese erst einmal abholen. Wir gehen zuerst wieder im Designer auf die Übersicht und machen einen Doppelklick auf die Activity eventDrivenActivity_Approver im Zustand stateApprover. Die Activity TaskChanged_Approver braucht zunächst wieder eine Methode, die bei Veränderungen an der Aufgabe aufgerufen werden. In unserem Fall ist dies die Methode OnTaskChanged_Approver: Innerhalb dieser Methode holen wir uns die Daten, welche der Benutzer im Aufgabenformular eingegeben hat ab und füllen unsere lokalen Variablen damit, damit die Daten nicht verloren gehen: private void onTaskChanged_Approver(object sender, ExternalDataEventArgs e) { try { _status = AfterProperties_Approver.ExtendedProperties["status"].ToString(); _comment = AfterProperties_Approver.ExtendedProperties["comment"].ToString(); } catch (Exception ex) { } }
Die Daten aus dem Aufgabenformular werden anhand der AfterProperties zurückgeliefert und sind über den Indexer ExtendedProperties zugänglich. Der Zugriff erfolgt sehr einfach über den Namen des Feldes im Aufgabenformular. Damit haben wir die Daten aus dem Aufgabenformular des Genehmigers abgeholt. Der nächste Schritt besteht nun darin, anhand der vom Benutzer eingegebenen Informationen im Workflow weiter zu verzweigen. Im Workflow Designer sehen wir, dass bei der if-else Verzweigung immer noch immer das rote Ausrufezeichen angezeigt wird. Beim Herunterklappen der Meldung sieht man, dass die Bedingung noch nicht definiert ist: Wenn wir auf die Fehlermeldung klicken landen wir in der Eigenschaft Condition der if-else Verzweigung (ifElseBranchActivity1). Beim Aufklappen dieser Eigenschaft sehen wir, dass wir entweder Regel hinterlegen können oder dass wir eine Methode implementieren können, die für die Verzweigung benutzt wird. In unserem Fall wählen wir Code Condition aus. Nun müssen wir noch die Methode angeben, die verwendet werden soll. In unserem Fall geben wir den Methodennamen IsApproved an. Beim Drücken der Eingabetaste landet man wieder im Code und im Designer sieht unsere Condition Eigenschaft also jetzt wie folgt aus: Innerhalb der Methode IsApproved fragen wir den Status ab, welcher vom InfoPath Aufgabenformular geliefert wurde. Dabei bedeutet „ok“, dass der Genehmiger genehmigt hat und „nok“, dass er zurückgewiesen hat. Unser Code bedarf deshalb keiner Raketentechnik und sieht wie folgt aus: private void IsApproved(object sender, ConditionalEventArgs e) { e.Result = false; if ("ok" == _status) { e.Result = true; } }
Die Eigenschaft Result aus den Ereignis Argumenten (ConditionalEventArgs) wird dabei von der if-else Verzweigung genutzt, um zu entscheiden, ob die Abfrage wahr oder falsch ist. Deshalb setzen wir e.Result auf true, wenn der Status „ok“ ist (Genehmiger hat genehmigt oder auf false, wenn der Genehmiger zurückgewiesen hat. Damit haben wir alles für die Aufgabe des Genehmigers erledigt. Das gleiche Spielchen wie oben beschrieben, müssen wir nun noch für den Zustand stateReviewer durchführen. Der Code für den gesamten Reviewer Zustand ist dabei wie folgt: #region Reviewer Task
public Guid TaskId_Reviewer = default(System.Guid); public SPWorkflowTaskProperties TaskProperties_Reviewer = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties(); public SPWorkflowTaskProperties AfterProperties_Reviewer = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties(); public SPWorkflowTaskProperties BeforeProperties_Reviewer = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
private void OnTaskCreate_Reviewer(object sender, EventArgs e) { TaskId_Reviewer = Guid.NewGuid(); TaskProperties_Reviewer.Title = "Bitte passen Sie das Dokument nochmal an."; TaskProperties_Reviewer.AssignedTo = workflowProperties.Originator; TaskProperties_Reviewer.Description = _instructions; TaskProperties_Reviewer.TaskType = 1; //Aufgaben Formular 2 TaskProperties_Reviewer.ExtendedProperties["comment"] = _comment; }
private void OnTaskChanged_Reviewer(object sender, ExternalDataEventArgs e) { try { _status = AfterProperties_Reviewer.ExtendedProperties["status"].ToString(); _instructions = AfterProperties_Reviewer.ExtendedProperties["instructions"].ToString(); } catch (Exception ex) { } }
private void SendToApprover(object sender, ConditionalEventArgs e) { e.Result = false; if ("approve" == _status) { e.Result = true; } }
Wie man in obigem Code sehen kann, wird eine neue Aufgabe an den Originator zugewiesen, also demjenigen, der den Workflow gestartet hat. Die bewirkt die folgende Zeile: TaskProperties_Reviewer.AssignedTo = workflowProperties.Originator; An diesem Beispiel kann man sehr schön erkennen, dass man auf etliche Parameter des Workflows Zugriff hat. Zum Abschluss dieses Teils noch ein kleiner Tipp: Der Workflow Designer in Visual Studio erzeugt einiges an Code. Dummerweise jedoch mehr oder weniger wahllos, je nachdem wie man die Eigenschaften der Activites füllt. Ich ordne diesen Code manuell um und verwende Regionen (#region), um einen besseren Überblick zu behalten. Ich bündele beispielsweise in einem State Machine Workflows alles, was zu einem Zustand gehört in einer #region. Mein Code für den Workflow sieht also nach der Umorganisation momentan wie folgt aus: Im herunter ladbaren Code Beispiel kann man das noch besser nachvollziehen. Damit haben alles beisammen, um den Workflow ablaufen zu lassen. Der Test des Workflows ist Bestandteil des nächsten Teils der Serie.