Dynamischer Rehosted Workflowdesigner für die WF 4 – Teil 2

Rückblick auf das Ziel von Teil 1: Die Vorteile der Prism-Architektur sind:

  • Möglichkeit die Prism-Module in eine bestehende Anwendung einzubauen
  • Möglichkeit nur die benötigten Module zu verwenden
  • Möglichkeit die Module beliebig anzuordnen

Nachdem es also das letzte Mal um die grundsätzliche auf Prism-Modulen basierende Infrastruktur ging, möchte ich nun ein spezielleres Modul vorstellen, das sich um Speicher- und Ladevorgänge kümmert. Natürlich soll man hier dynamisch die Datenquelle ändern können, also z. B. entscheiden können, ob man den Workflow aus einer Datenbank oder aus einer Datei liest. Sinnvoll ist es natürlich auch mehrere solche Speicheroptionen zur Verfügung zu stellen. Ich habe mich dafür entschieden ein Dialogfeld zu implementieren, was die Speicheroptionen anzeigt und aus dem heraus man neue Workflows erstellen oder andere laden bzw. löschen kann. Zu bedenken ist auch, dass beim Erstellen eines neuen Workflows verschiedene Root-Activities verwendet werden können sollen und damit auch die Toolbox abhängig vom „Workflow-Typ“ aufgebaut werden muss. Es ergibt sich damit das folgende Interface für  unsere Workflow-Typdefinition:

public interface IWorkflowType
{
    IToolboxCreatorService ToolboxCreatorService { get; }
    IStorageAdapter StorageAdapter { get; }
    string DisplayName { get; }
    string Description { get; }
}

Neben einer Beschreibung  und  einem Namen verweist der Workflowtyp auf zwei andere Interfaces, die Toolboxaufbau und Datenzugriffe kapseln. Das Interface für den Toolboxaufbau ist recht einfach, es liefert einfach eine Liste der Kategorien, die anzuzeigen sind. Im vorigen Artikel hatte ich ja schon das ToolboxModul erwähnt, das sich um das Laden der Toolbox kümmert. Dieses Modul nimmt später einfach wieder den ToolboxCreatorService entgegen.

Das Interface für die Datenzugriffe lässt sich in 2 Bereiche einteilen:

  • Abfrage von Name + Beschreibung aller im Datenspeicher vorhandenen Workflows
  • Abfragen der RootActivity und weiterer typspezifischer Daten

Der Grund für die Trennung ist natürlich die Performance. Es würde ewig dauern für alle Workflows ständig den Activity-Baum zu laden, zumal dieser ja zunächst noch aus XAML erzeugt werden muss. Workflow Description (Name + Beschreibung) und DesignerModel (RootActivity + weitere Daten) lassen sich über einen eindeutigen Schlüssel zuordnen, der abhängig von den Daten im DesignerModel ermittelt werden kann (wird z.B. dann beim Speichern ausgelesen).

public interface IStorageAdapter
{
    IEnumerable<IWorkflowDescription> GetAllWorkflowDescriptions();

    IDesignerModel CreateNewDesignerModel();
    bool CanCreateNewDesignerModel { get; }
    IDesignerModel GetDesignerModel(object key);
    bool SaveDesignerModel(IDesignerModel designerModel);
    bool DeleteDesignerModel(object key);
}

Hier mal ein Screenshot vom dazugehörigen Dialog:

Zusammengehalten und gesteuert wird das Ganze von einem eigenen Modul, was das Menüband oben erweitert. Durch WPF-Commands werden die Aktionen in zwei zentrale ViewModels weitergeleitet, die nach einigen Validierungen wieder die Interfaces aufrufen. Im nächsten Teil geht es dann um eine konkrete Implementierung der Interfaces.

Sourcecode:

Den kompletten (weiterentwickelten) Quellcode gibt es wieder hier.

Veröffentlicht von

Winfried

Student TU Chemnitz