Share via


Tâche 2 : incorporer le concepteur de workflow dans le Windows Form

Dans cette tâche, vous utiliserez la classe WorkflowLoader que vous avez créée dans Tâche 1 : créer le chargeur du concepteur de workflow et vous l'intégrerez dans le Windows Form que vous avez créé dans Tâche 2 : créer le Windows Form d'hébergement du concepteur de workflow. Le Windows Form contient un contrôle Panel utilisé pour héberger le concepteur de workflow Windows Workflow. Pour cela, vous devez créer un objet WorkflowView et l'ajouter à la collection d'activités enfants du contrôle Panel. Vous devez également ajouter le code utilisé pour analyser automatiquement les Xaml entrés dans le contrôle TextBox et passer le Xaml à l'objet WorkflowLoader pour affichez la définition de workflow résultante dans le concepteur de workflowWindows.

NoteRemarque :

Bien qu'il soit conseillé de suivre les exercices de façon linéaire, ce n'est pas obligatoire. Vous pouvez démarrer cet exercice en ouvrant l'exemple de projet et en continuant avec les étapes de la section suivante.

Pour implémenter l'interface IServiceProvider

  1. Implémentez l'interface IServiceProvider dans la classe WFEditForm créée dans Tâche 2 : créer le Windows Form d'hébergement du concepteur de workflow.

  2. Créez la méthode GetService requise pour l'implémentation du IServiceProvider.

    NoteRemarque :

    La méthode GetService masque l'implémentation de membre hérité ; par conséquent, vous devrez vous servir du mot clé new pour utiliser la méthode que vous définissez actuellement.

  3. Dans la méthode GetService, la valeur null est retournée (Nothing en Visual Basic) si le champ workflowView contient la valeur null. Sinon, appelez la méthode GetService du champ de classe workflowView, en passant serviceType en tant que paramètre à la méthode, comme l'illustre le code suivant :

    new public object GetService(Type serviceType)
    {
        return (this.workflowView != null) ? ((IServiceProvider)this.workflowView).GetService(serviceType) : null;
    }
    

Pour créer les champs et propriétés nécessaires pour l'hébergement du concepteur

  1. Dans la classe WFEditForm que vous avez créée dans Tâche 2 : créer le Windows Form d'hébergement du concepteur de workflow, créez les variables de membre suivantes :

    Type Nom

    WorkflowView

    workflowView

    DesignSurface

    designerSurface

    WorkflowLoader

    loader

    Activity

    currentWorkflow

    private WorkflowView workflowView;
    private DesignSurface designSurface;
    private WorkflowLoader loader;
    private Activity currentWorkflow;
    
  2. Dans la classe WFEditForm, créez une nouvelle propriété de type publicstring nommée Xaml qui contient à la fois un get et une méthode set.

  3. Dans la méthode get de la propriété Xaml, créez une variable locale string nommée xaml et initialisez-la dans une chaîne vide.

  4. Créez une instruction conditionnelle afin de garantir que la variable de classe du chargeur n'est pas null (Nothing en Visual Basic). Dans le corps de l'instruction conditionnelle, créez un bloc try/catch.

  5. Dans le corps du bloc try, appelez la méthode Flush de l'objet loader puis affectez à la variable locale xaml une valeur égale celle de la propriété Xaml de l'objet loader.

    NoteRemarque :

    Le bloc catch du bloc try correspondant contiendra un corps vide pour permettre à l'application d'analyser continuellement la propriété Xaml sans interrompre l'utilisateur en affichant des messages d'erreur.

  6. Utilisez la variable locale xaml en tant que valeur de retour de la méthodeget de la propriété Xaml. La méthode get de la propriété Xaml doit s'afficher comme le code suivant :

    get
    {
        string xaml = string.Empty;
        if (this.loader != null)
        {
            try
            {
                this.loader.Flush();
                xaml = this.loader.Xaml;
            }
            catch
            {
            }
        }
        return xaml;
    }
    
  7. Dans la méthode set de la propriété Xaml, créez un bloc try/catch.

  8. Dans le corps du bloc try créé à l'étape précédente, créez une instruction conditionnelle qui portera la valeur true si l'objet de valeur n'est ni null, ni vide. Pour cela, vous pouvez utiliser la méthode IsNullOrEmpty définie dans la classe String.

  9. Dans le corps de l'instruction conditionnelle, appelez la méthode LoadWorkflow, en passant à la méthode l'objet de valeur en tant que paramètre.

    NoteRemarque :

    La méthode LoadWorkflow sera définie au cours de la procédure suivante.

    set
    {
        try
        {
            if (!String.IsNullOrEmpty(value))
            {
                LoadWorkflow(value);
            }
        }
        catch
        {
        }
    }
    
  10. Le code de la propriété Xamlde la classe WFEditForm doit s'afficher comme suit :

    public string Xaml
    {
        get
        {
            string xaml = string.Empty;
            if (this.loader != null)
            {
                try
                {
                    this.loader.Flush();
                    xaml = this.loader.Xaml;
                }
                catch
                {
                }
            }
            return xaml;
        }
        set
        {
            try
            {
                if (!String.IsNullOrEmpty(value))
                {
                    LoadWorkflow(value);
                }
            }
            catch
            {
            }
        }
    }
    
  11. Dans la méthode xamlView_TextChanged, créez un bloc try/ catch.

  12. Dans le corps du bloc try créé à l'étape précédente, affectez à la propriété de classe Xaml la même valeur que celle de la propriété Text du contrôlexamlView TextBox.

    NoteRemarque :

    Un utilisateur recevrait des messages d'erreur en tapant dans le code Xaml ; par conséquent, le corps du bloc catch doit être vide afin de pouvoir intercepter toutes les exceptions levées.

    private void xamlView_TextChanged(object sender, EventArgs e)
    {
        try
        {
            this.Xaml = this.xamlView.Text;
        }
        catch { }
    }
    

Pour charger une nouvelle définition de workflow

  1. Dans la méthode OnLoad de la classe WFEditForm, appelez la méthode LoadNewSequentialWorkflow après l'appel de l'implémentation de classe de base de :OnLoad, tel qu'illustré dans le code suivant :

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        LoadNewSequentialWorkflow();
    }
    
  2. Dans la classe WFEditForm, créez une nouvelle méthode public nommée LoadNewSequentialWorkflow.

  3. Dans la méthode LoadNewSequentialWorkflow, créez une instance SequentialWorkflowActivity et assignez-la à la variable de classe currentWorkflow.

  4. Affectez à la propriété Name de la variable currentWorkflow une valeur égale à celle de la chaîne "CustomSequentialWorkflow".

  5. Appelez la méthode LoadWorkflow.

    NoteRemarque :

    La méthode LoadWorkflow sera définie au cours de la procédure suivante.

  6. Affectez à la propriété Text du contrôle xamlView TextBox une valeur égale à la valeur de retour de la méthode GetCurrentXaml.

    NoteRemarque :

    La méthode GetCurrentXaml est définie à l'étape suivante.

    La méthode LoadNewSequentialWorkflow doit s'afficher comme le code suivant :

    public void LoadNewSequentialWorkflow()
    {
        this.currentWorkflow = new SequentialWorkflowActivity();
        currentWorkflow.Name = "CustomSequentialWorkflow";
    
        this.LoadWorkflow();
        this.xamlView.Text = GetCurrentXaml();
    }
    
  7. Dans la classe WFEditForm, créez une nouvelle méthode nommée GetCurrentXaml, qui sera utilisée pour récupérer la représentation Xaml du workflow actuellement chargé dans le concepteur de workflow.

  8. Dans la méthode GetCurrentXaml, créez un objet IDesignerHost nommé host initialisez-le en appelant GetService, en passant le System.Type de l'interface IDesignerHost en tant que paramètre.

  9. Créez une instruction conditionnelle pour vérifier que l'objet hôte et la propriété RootComponent de l'objet host ne portent pas la valeur null (Nothing en Visual Basic).

  10. Dans le corps de l'instruction conditionnelle créée à l'étape précédente, utilisez la classe WorkflowMarkupSerializer pour sérialiser la propriété RootComponent de l'objet hôte à l'aide d'un XmlWriter créé avec un StringWriter.

  11. Retournez la chaîne Xaml à l'aide de la méthode ToString de la classe StringWriter créée à l'étape précédente. La méthode GetCurrentXaml doit s'afficher comme le code suivant :

    private string GetCurrentXaml()
    {
        IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
    
        if (host != null && host.RootComponent != null)
        {
            Activity rootActivity = host.RootComponent as Activity;
    
            if (rootActivity != null)
            {
                using (StringWriter sw = new StringWriter())
                {
                    using (XmlWriter writer = XmlWriter.Create(sw))
                    {
                        WorkflowMarkupSerializer xomlSerializer = new WorkflowMarkupSerializer();
                        xomlSerializer.Serialize(writer, rootActivity);
                    }
    
                    return sw.ToString();
                }
            }
        }
    
        return "";
    }
    

Pour charger des définitions de workflow

  1. Dans la classe WFEditForm, créez une méthode private nommée LoadWorkflow.

  2. Dans la méthode LoadWorkflow, utilisez la classe WorkflowMarkupSerializer pour sérialiser la variable de classe currentWorkflow à l'aide d'un XmlWriter créé avec un StringWriter.

  3. Affectez à la propriété de classe Xaml une valeur égale à la valeur de retour de la méthode ToString de l'objet StringWriter créé à l'étape précédente. La méthode LoadWorkflow doit s'afficher comme les éléments suivants :

    private void LoadWorkflow()
    {
        using (StringWriter stringWriter = new StringWriter())
        {
            using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter))
            {
                WorkflowMarkupSerializer serializer = new WorkflowMarkupSerializer();
                serializer.Serialize(xmlWriter, currentWorkflow);
                this.Xaml = stringWriter.ToString();
            }
        }
    }
    
  4. Dans la classe WFEditForm, créez une nouvelle méthode privatenommée LoadWorkflow qui accepte une string nommée xaml en tant que parameter et retourne un objet ICollection.

  5. Dans la méthode LoadWorkflow créée à l'étape précédente, créez une variable locale WorkflowLoader nommée loader et créez une nouvelle instance de cet objet.

  6. Affectez à la propriété Xaml de l'objet chargeur créé à l'étape précédente une valeur égale à celle du paramètre xaml passé dans la méthode.

  7. Retournez hors de la méthode en appelant la méthode LoadWorfklow, en passant l'objet WorkflowLoader en tant que paramètre à cette méthode.

    NoteRemarque :

    Vous créerez la méthode LoadWorkflow surchargée pour cette étape au cours de l'étape suivante.

    private ICollection LoadWorkflow(string xaml)
    {
        WorkflowLoader loader = new WorkflowLoader();
        loader.Xaml = xaml;
        return LoadWorkflow(loader);
    }
    
  8. Dans la classe WFEditForm, créez une nouvelle méthode nommée LoadWorkflow qui accepte un objet WorkflowLoader nommé loader en tant que paramètre et retourne un objet ICollection.

  9. Dans la méthode LoadWorkflow créée à l'étape précédente, créez un bloc try-catch-finally.

  10. Dans le bloc try créé à l'étape 9, appelez la méthode SuspendLayout.

  11. Créez un nouvel objet DesignSurface nommé designSurface et créez une nouvelle instance de cet objet.

  12. Appelez la méthode BeginLoad de l'objet DesignSurface créé à l'étape précédente, en passant l'objet WorkflowLoader en tant que paramètre.

  13. Si la propriété Count de la collection LoadErrors définie dans l'objet designSurface est supérieure à 0, retournez la propriété LoadErrors de la méthode. Le bloc try doit à cette étape s'afficher comme les éléments suivants :

    SuspendLayout();
    
    DesignSurface designSurface = new DesignSurface();
    designSurface.BeginLoad(loader);
    if (designSurface.LoadErrors.Count > 0)
        return designSurface.LoadErrors;
    
  14. Après le code que vous avez ajouté au bloc try au cours des étapes 10-13, obtenez l'objet IDesignerHost actuel en appelant la méthode GetService de l'objet designSurface, en passant IDesignerHostType en tant que paramètre.

  15. Créez une instruction conditionnelle qui portera la valeur true si designerHost et designerHost.RootComponent ne portent pas la valeur null (Nothing en Visual Basic).

  16. Dans le corps de l'instruction conditionnelle créée à l'étape précédente, obtenez le concepteur du RootComponent en appelant la méthode GetDesigner à partir du designerHost, en passant la propriété RootComponent de l'objet designerHost. Cette méthode retourne un objet IRootDesigner.

  17. Créez une autre instruction conditionnelle qui portera la valeur true si l'objet rootDesigner ne porte pas la valeur null (Nothing en Visual Basic).

  18. Dans le corps de l'instruction conditionnelle créée à l'étape précédente, appelez la méthode UnloadWorkflow. Cette méthode sera définie au cours de la procédure suivante.

  19. Affectez au champ de classe designSurface une valeur égale à celle de la variable locale designSurface.

  20. Affectez au champ de classe loader une valeur égale à celle de la variable locale loader.

  21. Appelez la méthode GetView de l'objet rootDesigner, en passant ViewTechnology.Default en tant que paramètre et affectez au champ de classe workflowView une valeur égale à celle de la valeur de retour de cette méthode. Vous devrez effectuer un cast du résultat en un objet WorkflowView, car GetView retourne un Object.

  22. Ajoutez le champ de classe workflowView au contrôle Panel (placeHolderPanel) de la classe Windows Form en appelant la méthode Add de la collection Controls, en passant l'objet workflowView à cette méthode en tant que paramètre.

  23. Vérifiez que l'objet workflowView remplit le contenu entier du contrôle Panel en affectant à la propriété Dock de l'objet workflowView la valeur DockStyle.Fill.

  24. Le bloc try que vous avez créé aux étapes 9 à 23 doit s'afficher comme le code suivant :

    try
    {
        SuspendLayout();
    
        DesignSurface designSurface = new DesignSurface();
        designSurface.BeginLoad(loader);
        if (designSurface.LoadErrors.Count > 0)
            return designSurface.LoadErrors;
    
        IDesignerHost designerHost = designSurface.GetService(typeof(IDesignerHost)) as IDesignerHost;
        if (designerHost != null && designerHost.RootComponent != null)
        {
            IRootDesigner rootDesigner = designerHost.GetDesigner(designerHost.RootComponent) as IRootDesigner;
            if (rootDesigner != null)
            {
                UnloadWorkflow();
    
                this.designSurface = designSurface;
                this.loader = loader;
                this.workflowView = rootDesigner.GetView(ViewTechnology.Default) as WorkflowView;
                this.placeHolderPanel.Controls.Add(this.workflowView);
                this.workflowView.Dock = DockStyle.Fill;
            }
        }
    }
    
  25. Dans le bloc finally qui suit le try/ bloccatch, appelez la méthode ResumeLayout, en passant true en tant que paramètre.

  26. À la fin de la méthode LoadWorkflow créée aux étapes précédentes, la valeur null (Nothing en Visual Basic) est retournée, car aucune erreur n'a été rencontrée lorsque la définition de workflow a été chargée.

  27. La méthode LoadWorkflow que vous avez créée aux étapes 8 à 26 doit s'afficher comme le code suivant :

    private ICollection LoadWorkflow(WorkflowLoader loader)
    {
        try
        {
            SuspendLayout();
    
            DesignSurface designSurface = new DesignSurface();
            designSurface.BeginLoad(loader);
            if (designSurface.LoadErrors.Count > 0)
                return designSurface.LoadErrors;
    
            IDesignerHost designerHost = designSurface.GetService(typeof(IDesignerHost)) as IDesignerHost;
            if (designerHost != null && designerHost.RootComponent != null)
            {
                IRootDesigner rootDesigner = designerHost.GetDesigner(designerHost.RootComponent) as IRootDesigner;
                if (rootDesigner != null)
                {
                    UnloadWorkflow();
    
                    this.designSurface = designSurface;
                    this.loader = loader;
                    this.workflowView = rootDesigner.GetView(ViewTechnology.Default) as WorkflowView;
                    this.placeHolderPanel.Controls.Add(this.workflowView);
                    this.workflowView.Dock = DockStyle.Fill;
                }
            }
        }
    
        catch { }
    
        finally
        {
            ResumeLayout(true);
        }
    
        return null;
    }
    

Pour décharger une définition de workflow

  1. Dans la classe WFEditForm, créez une nouvelle méthode private nommée UnloadWorkflow.

  2. Dans la méthode UnloadWorkflow, appelez la méthode GetService, en passant un objet IDesignerHostType en tant que paramètre et assignez la valeur de retour à une nouvelle variable locale IDesignerHost nommée designerHost.

  3. Créez une nouvelle instruction conditionnelle qui prendra la valeur true si l'objet designerHost ne porte pas la valeur null (Nothing en Visual Basic) et si la valeur de la propriété designerHost.Container.Components.Count est supérieure à 0.

  4. Dans le corps de l'instruction conditionnelle créée à l'étape précédente, appelez la méthode static DestroyObjectGraphFromDesignerHost définie dans la classe WorkflowLoader, en passant l'objet designerHost et l'objet designerHost.RootComponent à la méthode en tant que paramètres.

  5. Créez une instruction conditionnelle qui portera la valeur true si l'objet designSurface ne porte pas la valeur null (Nothing en Visual Basic).

  6. Dans le corps de l'instruction conditionnelle créée à l'étape précédente, appelez la méthode Dispose de l'objet designSurface et affectez à l'objet designSurface la valeur null (Nothing en Visual Basic).

  7. Créez une instruction conditionnelle qui portera la valeur true si l'objet workflowView ne porte pas la valeur null (Nothing en Visual Basic).

  8. Dans le corps de l'instruction conditionnelle créé à l'étape précédente, appelez la méthode Remove de la collection Controls du contrôle Panel (placeHolderPanel), en passant l'objet workflowView en tant que paramètre, appelez la méthode Dispose de l'objet workflowView et affectez à l'objet workflowView la valeur null (Nothing en Visual Basic).

  9. La méthode UnloadWorkflow créée dans cette procédure doit s'afficher comme les éléments suivants :

Compilation du code

Pour plus d'informations sur la compilation du code, consultez Compilation du code.

Dans la prochaine tâche, Tâche 3 : créer le WorkflowMenuCommandService, vous allez ajouter un service au concepteur de workflow pour activer le menu contextuel de ce dernier et ses commandes spécifiques au workflow associées définies dans Windows Workflow Foundation.

Voir aussi

Concepts

Hébergement de concepteurs de workflows

Autres ressources

Basic Designer Hosting Sample
Outlook Workflow Wizard Sample
Workflow Monitor Sample
Tracking Profile Designer Sample

Footer image

Copyright ©2007 par Microsoft Corporation. Tous droits réservés.