Share via


Tâche 1 : créer le chargeur du concepteur de workflow

Dans cette tâche, vous allez créer la classe responsable du chargement et du déchargement d'une définition de workflow. Vous y parviendrez en dérivant de la classe WorkflowDesignerLoader. La classe WorkflowDesignerLoader peut être implémentée pour prendre en charge le chargement personnalisé d'un concepteur de workflow et de ses composants. Un chargeur de concepteur de workflow se charge également d'écrire les modifications apportées à un document ouvert dans un emplacement de stockage utilisé par le chargeur lors du chargement du document, après que la méthode Flush ait été appelée.

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 créer le fichier de code source WorkflowDesignerLoader

  1. Dans votre répertoire de projets, créez un nouveau fichier nommé Loader.
    Attribuez une extension .cs au fichier si vous créez une application C# ou .vb si vous créez une application Visual Basic.

  2. Dans votre fichier projet principal (WFEdit), dans l'élément ItemGroup que vous avez créé dans la première procédure, ajoutez un nouvel élément Compile.

  3. Ajoutez un nouvel attribut à l'élément Compile, nommé Include.

    Utilisez le nom de fichier que vous avez créé à l'étape 1 comme valeur d'attribut.

  4. Votre nœud ItemGroup final s'affichera comme suit :

    <ItemGroup>
        <Compile Include="Loader.vb" />
        <Compile Include="WFEditForm.vb">
            <SubType>Form</SubType>
        </Compile>
        <Compile Include="Program.vb" />
    </ItemGroup>
    
    <ItemGroup>
        <Compile Include="Loader.cs" />
        <Compile Include="WFEditForm.cs">
            <SubType>Form</SubType>
        </Compile>
        <Compile Include="Program.cs" />
    </ItemGroup>
    

Pour créer la classe WorkflowLoader

  1. Dans le fichier Loader que vous avez créé dans la procédure précédente, créez un bloc d'espace de noms à l'aide du même espace de noms que le code source Windows Form. Pour ce didacticiel, l'espace de noms est Microsoft.Samples.Workflow.Quickstarts.WFEdit.

    ' To be provided
    
    namespace Microsoft.Samples.Workflow.Quickstarts.WFEdit
    {
    }
    
  2. Ajoutez les directives d'espace de noms suivantes pour importer les types dont vous aurez besoin pour la classe WorkflowLoader. Ces directives doivent être placées dans le bloc d'espace de noms que vous avez créé à l'étape précédente.

    using System;
    using System.IO;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.ComponentModel.Design.Serialization;
    using System.Workflow.ComponentModel;
    using System.Workflow.ComponentModel.Compiler;
    using System.Workflow.ComponentModel.Design;
    using System.Workflow.ComponentModel.Serialization;
    using System.Collections;
    using System.Collections.Generic;
    using System.Xml;
    using System.Windows.Forms;
    
  3. Créez une classe sealed interne nommée WorkflowLoader dérivée de la classe WorkflowDesignerLoader.

    ' To be provided
    
    internal sealed class WorkflowLoader : WorkflowDesignerLoader
    {
    }
    
  4. Dans la classe WorkflowLoader que vous avez créée à l'étape précédente, créez une variable privatestring nommée xaml et initialisez-la dans une chaîne vide.

  5. Créez une propriété de type publicstring nommée Xaml et définissez les méthodes get et set pour retourner et définir, respectivement, la variable privatestring que vous avez créée à l'étape précédente.

    private string xaml = string.Empty;
    
    public string Xaml
    {
        get
        {
            return this.xaml;
        }
    
        set
        {
            this.xaml = value;
        }
    }
    
  6. Substituez la méthode Initialize protégée dans la classe WorkflowLoader et appelez l'implémentation de la classe de base d'Initialize dans la définition de la méthode.

  7. Substituez la méthode public Dispose dans la classe WorkflowLoader et appelez l'implémentation de la classe de base de Dispose dans la définition de la méthode.

    protected override void Initialize()
    {
        base.Initialize();
    }
    
    public override void Dispose()
    {
        base.Dispose();
    }
    
  8. Substituez la propriété de type publicstring nommée FileName et définissez une méthode get. Dans la définition de la méthode get, renvoyez null (Nothing en Visual Basic).

    NoteRemarque :

    Ce didacticiel n'utilisera pas de stockage de fichier pour enregistrer des définitions de workflow. Toutes les définitions de workflow sont créées en mémoire mais ne sont pas enregistrées pour une autre utilisation après la fermeture de l'application. Par conséquent, toutes les méthodes liées au stockage de fichier dans la classe WorkflowLoader retourneront null pour leurs implémentations.

  9. Substituez la méthode GetFileReader à l'aide d'une string nommée filePath en tant que paramètre. Cette méthode doit retourner null (Nothing en Visual Basic) dans sa définition.

  10. Substituez la méthode GetFileWriter à l'aide d'une string nommée filePath en tant que paramètre. Cette méthode doit retourner null (Nothing en Visual Basic) dans sa définition.

    public override string FileName
    {
        get
        {
            return null;
        }
    }
    
    public override TextReader GetFileReader(string filePath)
    {
        return null;
    }
    
    public override TextWriter GetFileWriter(string filePath)
    {
        return null;
    }
    

Pour charger des définitions de workflow à l'aide de WorkflowLoader

  1. Dans la classe WorkflowLoader que vous avez créée dans la procédure précédente, substituez la méthode PerformLoad protégée. Cette méthode prévoit qu'un objet IDesignerSerializationManager serve de paramètre à la méthode.

    ' To be provided
    
    protected override void PerformLoad(IDesignerSerializationManager serializationManager)
    {
    }
    
  2. Dans la méthode PerformLoad, créez une variable Activity locale nommée rootActivity et initialisez-la à null (Nothing en Visual Basic).

  3. Dans la méthode PerformLoad, créez une variable IDesignerHost locale nommée designerHost. Initialisez cette variable en appelant la méthode GetService, en passant le type de l'interface IDesignerHost.

  4. Créez une variable TextReader locale dans la méthode PerformLoad et initialisez-la en créant un nouvel objet StringReader, en passant le champ xaml de la classe WorkflowLoader comme un paramètre au constructeur StringReader. À ce stade, la méthode PerformLoaddoit s'afficher comme le code suivant :

    Activity rootActivity = null;
    IDesignerHost designerHost = (IDesignerHost)GetService(typeof(IDesignerHost));
    TextReader reader = new StringReader(this.xaml);
    
  5. À la suite de la déclaration des variables locales que vous avez créées aux étapes précédentes, créez un bloc try. Dans le bloc try, créez un XmlReader nommé xmlReader et initialisez-le à l'aide de la méthode static Create de la classe XmlReader, en passant la variable de lecteur locale vous avez créée à l'étape 4.

  6. Créez une nouvelle variable WorkflowMarkupSerializer locale nommée xomlSerializer et créez une nouvelle instance de cette classe.

  7. Appelez la méthode Deserialize de l'objet WorkflowMarkupSerializer que vous avez créée à l'étape précédente, en passant la variable locale xmlReader comme un paramètre à la méthode. Effectuez un cast de la valeur de retour à un objet Activity et affectez-la à la variable locale rootActivity que vous avez créée à l'étape 2.

  8. Créez un bloc catch suivant le bloc try vous avez créé à l'étape 5. Utilisez le type WorkflowMarkupSerializationException en guise d'exception à intercepter. Cette exception sera ignorée, le corps du bloc catch sera donc vide.

  9. Créez un bloc finally à la suite du bloc catch que vous avez créé à l'étape précédente. Dans le corps du bloc finally, appelez la méthode Close de l'objet TextReader vous avez créé à l'étape 4. Le bloc try-catch-finally doit s'afficher comme le code suivant :

    try
    {
        using (XmlReader xmlReader = XmlReader.Create(reader))
        {
            WorkflowMarkupSerializer xomlSerializer = new WorkflowMarkupSerializer();
            rootActivity = xomlSerializer.Deserialize(xmlReader) as Activity;
        }
    }
    catch (WorkflowMarkupSerializationException)
    {
    }
    finally
    {
        reader.Close();
    }
    
  10. À la suite du try-catch-finally que vous avez créé aux étapes précédentes, créez une instruction conditionnelle garantissant que les variables locales rootActivity et designerHost ne sont pas null (Nothing en Visual Basic). Si cette instruction est true, appelez la méthode AddObjectGraphToDesignerHost, en passant les variables designerHost et rootActivity en tant que paramètres à la méthode.

    NoteRemarque :

    La méthode AddObjectGraphToDesignerHost sera définie dans la procédure suivante.

    if (rootActivity != null && designerHost != null)
    {
        AddObjectGraphToDesignerHost(designerHost, rootActivity);
    }
    
  11. La méthode PerformLoad que vous avez définie dans cette procédure doit s'afficher comme le code suivant :

    protected override void PerformLoad(IDesignerSerializationManager serializationManager)
    {
        Activity rootActivity = null;
        IDesignerHost designerHost = (IDesignerHost)GetService(typeof(IDesignerHost));
        TextReader reader = new StringReader(this.xaml);
    
        try
        {
            using (XmlReader xmlReader = XmlReader.Create(reader))
            {
                WorkflowMarkupSerializer xomlSerializer = new WorkflowMarkupSerializer();
                rootActivity = xomlSerializer.Deserialize(xmlReader) as Activity;
            }
        }
        catch (WorkflowMarkupSerializationException)
        {
        }
        finally
        {
            reader.Close();
        }
    
        if (rootActivity != null && designerHost != null)
        {
            AddObjectGraphToDesignerHost(designerHost, rootActivity);
        }
    }
    

Pour ajouter des activités à l'hôte du concepteur de workflow

  1. Dans la classe WorkflowLoader, créez une nouvelle méthode privatestatic nommée AddObjectGraphToDesignerHost à l'aide d'un objet IDesignerHost nommé designerHost et d'un objet Activity nommé activity en tant que paramètres à la méthode.

    ' To be provided
    
    private static void AddObjectGraphToDesignerHost(IDesignerHost designerHost, Activity activity)
    {
    }
    
  2. Dans la méthode AddObjectGraphToDesignerHost, créez une variable de chaîne nommée fullClassName et initialisez-la en accédant à la propriété FullName de l'objet Type retourné par la méthode GetType du paramètre activity.

  3. Créez une variable de chaîne nommée rootSiteName et initialisez-la à l'aide de la sous-chaîne du fullClassName qui correspond à la dernière partie de la chaîne suivant immédiatement le dernier point de cette chaîne. Par exemple, si le fullClassName est égal à System.Workflow.Activities.SequentialWorkflowActivity, rootSiteName serait égal à SequentialWorkflowActivity. Le code suivant indique comment déclarer et initialiser les variables locales fullClassName et rootSiteName.

    string fullClassName = activity.GetType().FullName;
    string rootSiteName = (fullClassName.LastIndexOf('.') != -1) ? fullClassName.Substring(fullClassName.LastIndexOf('.') + 1) : fullClassName;
    
  4. Ajoutez l'objet activity à la collection Container de l'objet designerHost, en passant les objets activity et rootSiteName en tant que paramètres à la méthode Add de la collection.

  5. Si l'objet activity est une CompositeActivity, énumérez chaque activité enfant en appelant la méthode GetNestedActivities, en passant l'objet activity en tant que paramètre et en ajoutant chaque activité enfant à la collection designerHost Container.

    NoteRemarque :

    La méthode GetNestedActivities sera définie dans la procédure suivante.

    designerHost.Container.Add(activity, rootSiteName);
    
    if (activity is CompositeActivity)
    {
        foreach (Activity childActivity in GetNestedActivities(activity as CompositeActivity))
            designerHost.Container.Add(childActivity, childActivity.QualifiedName);
    }
    
  6. La dernière méthode AddObjectGraphToDesignerHost doit s'afficher comme le code suivant :

    private static void AddObjectGraphToDesignerHost(IDesignerHost designerHost, Activity activity)
    {
        string fullClassName = activity.GetType().FullName;
        string rootSiteName = (fullClassName.LastIndexOf('.') != -1) ? fullClassName.Substring(fullClassName.LastIndexOf('.') + 1) : fullClassName;
    
        designerHost.Container.Add(activity, rootSiteName);
    
        if (activity is CompositeActivity)
        {
            foreach (Activity childActivity in GetNestedActivities(activity as CompositeActivity))
                designerHost.Container.Add(childActivity, childActivity.QualifiedName);
        }
    }
    

Pour créer un tableau d'activités enfants imbriquées

  1. Dans la classe WorkflowLoader, créez une nouvelle méthode privatestatic nommée GetNestedActivities qui accepte un paramètre CompositeActivity nommé compositeActivity et retourne un tableau d'objets Activity.

    ' To be provided
    
    private static Activity[] GetNestedActivities(CompositeActivity compositeActivity)
    {
    }
    
  2. Dans la méthode GetNestedActivities, levez une nouvelle exception ArgumentNullException si le paramètre compositeActivity passé dans la méthode est null (Nothing en Visual Basic).

    if (compositeActivity == null)
        throw new ArgumentNullException("compositeActivity");
    
  3. Créez un objet ArrayList nommé nestedActivities et une instance de ce type.

  4. Créez un objet Queue nommé compositeActivities et une instance de ce type.

  5. Ajoutez l'objet compositeActivity passé en tant que paramètre à la méthode GetNestedActivities dans la file d'attente compositeActivities en appelant la méthode Enqueue.

    ArrayList nestedActivities = new ArrayList();
    Queue compositeActivities = new Queue();
    compositeActivities.Enqueue(compositeActivity);
    
  6. Créez une boucle while que vérifiera la propriété Count de l'objet compositeActivities et continuera la boucle si le Count est supérieur à 0.

  7. Dans la boucle while, créez une variable CompositeActivity nommée currentCompositeActivity et initialisez-la en appelant la méthode Dequeue de la collection compositeActivities.

  8. Énumérez la collection Activities de l'objet currentCompositeActivity à l'aide d'une boucle foreach et ajoutez la Activity enfant résultante à la collection nestedActivities. En outre, si l'activité enfant est une CompositeActivity, ajoutez-la à la collection compositeActivities en appelant la méthode Enqueue.

  9. La boucle while que vous avez créée aux étapes 6 à 8 doit s'afficher comme le code suivant :

    while (compositeActivities.Count > 0)
    {
        CompositeActivity currentCompositeActivity = (CompositeActivity)compositeActivities.Dequeue();
    
        foreach (Activity activity in currentCompositeActivity.Activities)
        {
            nestedActivities.Add(activity);
            if (activity is CompositeActivity)
                compositeActivities.Enqueue(activity);
        }
    }
    
  10. Convertissez la collection nestedActivities ArrayList en un tableau d'objets Activity en appelant la méthode ToArray et en passant le Type de la classe Activity. Vous devrez effectuer un cast du résultat dans un tableau Activity. L'ensemble de la méthode GetNestedActivities doit s'afficher comme le code suivant :

    private static Activity[] GetNestedActivities(CompositeActivity compositeActivity)
    {
        if (compositeActivity == null)
            throw new ArgumentNullException("compositeActivity");
    
        ArrayList nestedActivities = new ArrayList();
        Queue compositeActivities = new Queue();
        compositeActivities.Enqueue(compositeActivity);
    
        while (compositeActivities.Count > 0)
        {
            CompositeActivity currentCompositeActivity = (CompositeActivity)compositeActivities.Dequeue();
    
            foreach (Activity activity in currentCompositeActivity.Activities)
            {
                nestedActivities.Add(activity);
                if (activity is CompositeActivity)
                    compositeActivities.Enqueue(activity);
            }
        }
        return (Activity[])nestedActivities.ToArray(typeof(Activity));
    }
    

Pour retirer les activités de l'hôte du concepteur

  1. Dans la classe WorkflowLoader, créez une nouvelle méthode static nommée DestroyObjectGraphFromDesignerHost qui accepte un objet IDesignerHost nommé designerHost et une Activity nommée activity en tant que paramètres.

    ' To be provided
    
    private static Activity[] GetNestedActivities(CompositeActivity compositeActivity)
    {
    }
    
  2. Dans la méthode DestroyObjectGraphFromDesignerHost, levez une nouvelle ArgumentNullException si le paramètre designerHost ou activity passé dans la méthode est null (Nothing en Visual Basic).

    if (designerHost == null)
        throw new ArgumentNullException("designerHost");
    if (activity == null)
        throw new ArgumentNullException("activity");
    
  3. Appelez la méthode DestroyComponent de l'objet designerHost, en passant l'objet activity en tant que paramètre à la méthode.

  4. Si l'objet d'activité est une CompositeActivity, énumérez chaque activité enfant de l'activity à l'aide de la méthode GetNestedActivities que vous avez créée dans la procédure précédente. Pour chaque activité enfant, appelez la méthode DestroyComponent, en passant l'activité enfant comme un paramètre à cette méthode comme affiché dans le code suivant :

    designerHost.DestroyComponent(activity);
    
    if (activity is CompositeActivity)
    {
        foreach (Activity activity2 in GetNestedActivities(activity as CompositeActivity))
            designerHost.DestroyComponent(activity2);
    }
    
  5. La dernière méthode DestroyObjectGraphFromDesignerHost doit s'afficher comme le code suivant :

    internal static void DestroyObjectGraphFromDesignerHost(IDesignerHost designerHost, Activity activity)
    {
        if (designerHost == null)
            throw new ArgumentNullException("designerHost");
        if (activity == null)
            throw new ArgumentNullException("activity");
    
        designerHost.DestroyComponent(activity);
    
        if (activity is CompositeActivity)
        {
            foreach (Activity activity2 in GetNestedActivities(activity as CompositeActivity))
                designerHost.DestroyComponent(activity2);
        }
    }
    

Compilation du code

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

À l'étape suivante, vous ajouterez le code nécessaire à la classe Windows Form vous avez créée dans Tâche 2 : créer le Windows Form d'hébergement du concepteur de workflow pour utiliser la classe WorkflowLoader que vous avez créée dans cette tâche. Lorsque la tâche sera effectuée, le concepteur de workflow Windows sera visible à partir de votre application Windows Form.

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.