Share via


Tâche 3 : créer le WorkflowMenuCommandService

Dans la tâche 2, vous avez intégré la classe WorkflowLoader que vous avez créée dans la tâche 1 avec l'application Windows Form WFEdit. À ce stade, le Concepteur Windows Workflow Foundation est visible lorsque l'application s'exécute. Dans cette tâche, 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.

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 Services

  1. Dans le répertoire de projets, créez un nouveau fichier nommé Services.
    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 le fichier projet principal (WFEdit), dans l'élément ItemGroup que vous avez créé dans Tâche 2 : créer le Windows Form d'hébergement du concepteur de workflow, 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. Le nœud ItemGroup final apparaît comme suit :

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

Pour créer la classe WorkflowMenuCommandService

  1. Dans le fichier Services que vous avez créé dans la procédure précédente, créez un bloc Namespace à 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 Namespace que vous avez créé à l'étape précédente.

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.Design;
    using System.Workflow.ComponentModel;
    using System.Workflow.ComponentModel.Design;
    using System.Windows.Forms;
    using System.Drawing;
    
  3. Créez une classe sealed interne nommée WorkflowMenuCommandService dérivée de la classe MenuCommandService.

    ' To be provided
    
    internal sealed class WorkflowMenuCommandService : MenuCommandService
    {
    }
    
  4. Dans la classe WorkflowMenuCommandService, créez un constructeur public qui accepte un objet IServiceProvider nommé serviceProvider en tant que paramètre. En outre, appelez l'implémentation de classe de base du constructeur tel qu'illustré dans le code suivant :

    public WorkflowMenuCommandService(IServiceProvider serviceProvider)
        : base(serviceProvider)
    {
    }
    

Pour créer la méthode ShowContextMenu

  1. Dans la classe WorkflowMenuCommandService, remplacez la méthode ShowContextMenu. Cette méthode accepte un objet CommandID nommé menuID, un Int32 nommé x et un Int32 nommé y en tant que paramètres.

    ' To be provided
    
    public override void ShowContextMenu(CommandID menuID, int x, int y)
    {
    }
    
  2. Dans la méthode ShowContextMenu, créez une instruction conditionnelle qui correspond à true si le paramètre menuID a la valeur System.Workflow.ComponentModel.Design.WorkflowMenuCommands.SelectionMenu. Ainsi, le menu contextuel dans le concepteur hébergé s'affiche uniquement lorsqu'un utilisateur clique avec le bouton droit de la souris sur une activité de workflow.

    NoteRemarque :

    Le code restant dans les étapes suivantes pour cette méthode doit être placé dans le corps de l'instruction conditionnelle.

  3. Dans le bloc true de l'instruction conditionnelle créée à l'étape précédente, créez un nouvel objet ContextMenu nommé contextMenu et créez une nouvelle instance de cette classe.

  4. Créez un bloc d'énumérateur qui énumère chaque DesignerVerb dans la collection Verbs.

  5. Dans le bloc d'énumération créé à l'étape précédente, créez un objet MenuItem nommé menuItem, puis créez une instance de cette classe à l'aide de verb.Text comme premier paramètre du constructeur et un nouvel objet EventHandler à l'aide du délégué OnMenuClicked en tant que deuxième paramètre. La méthode déléguée OnMenuClicked sera créée dans une étape ultérieure.

  6. Affectez la valeur du DesignerVerb actuellement énuméré, nommé verb, à la propriété Tag de l'objet menuItem créé à l'étape précédente.

  7. Ajoutez l'élément de menu que vous avez créé à l'étape 6 à la collection MenuItems de l'objet contextMenu à l'aide de la méthode Add. Le code suivant montre comment le bloc d'énumération doit s'afficher :

    ContextMenu contextMenu = new ContextMenu();
    
    foreach (DesignerVerb verb in Verbs)
    {
        MenuItem menuItem = new MenuItem(verb.Text, new EventHandler(OnMenuClicked));
        menuItem.Tag = verb;
        contextMenu.MenuItems.Add(menuItem);
    }
    
  8. À la suite du bloc d'énumération vous avez créé dans les étapes précédentes, créez un tableau MenuItem nommé items et initialisez-le à l'aide de la méthode GetSelectionMenuItems.

    NoteRemarque :

    La méthode GetSelectionMenuItems sera créée dans la procédure suivante.

  9. Créez une nouvelle instruction conditionnelle qui correspond à true si la propriété Length du tableau items est supérieure à 0.

  10. Dans le corps true de l'instruction conditionnelle créée à l'étape précédente, ajoutez un nouvel objet MenuItem, passant "-" en tant que paramètre du constructeur et ajoutez-le à la collection MenuItems de l'objet contextMenu à l'aide de la méthode Add.

  11. À la suite du code créé à l'étape précédente, énumérez chaque objet MenuItem dans le tableau d'éléments et ajoutez chaque élément à la collection MenuItems de l'objet contextMenu à l'aide de la méthode Add. Le code permettant de créer le tableau d'éléments et le code permettant d'ajouter chaque élément de menu de sélection à l'objet contextMenu doivent apparaître comme suit :

    MenuItem[] items = GetSelectionMenuItems();
    if (items.Length > 0)
    {
        contextMenu.MenuItems.Add(new MenuItem("-"));
        foreach (MenuItem item in items)
            contextMenu.MenuItems.Add(item);
    }
    
  12. À la suite du bloc d'instruction conditionnelle créé à l'étape 10, créez un nouvel objet WorkflowView nommé workflowView et initialisez-le à l'aide de la méthode GetService. Passez l'objet Type de la classe WorkflowView en tant que paramètre à la méthode GetService.

  13. Créez une instruction conditionnelle pour garantir que l'objet workflowView n'a pas la valeur null (Nothing en Visual Basic) et appelez la méthode Show de l'objet contextMenu. Les paramètres de la méthode Show incluent l'objet workflowView et le résultat de l'appel de la méthode workflowView.PointToClient, passant un nouvel objet Point initialisé à l'aide des paramètres de méthode x et y. Le code de ShowContextMenu doit apparaître comme suit :

    public override void ShowContextMenu(CommandID menuID, int x, int y)
    {
        if (menuID == WorkflowMenuCommands.SelectionMenu)
        {
            ContextMenu contextMenu = new ContextMenu();
    
            foreach (DesignerVerb verb in Verbs)
            {
                MenuItem menuItem = new MenuItem(verb.Text, new EventHandler(OnMenuClicked));
                menuItem.Tag = verb;
                contextMenu.MenuItems.Add(menuItem);
            }
    
            MenuItem[] items = GetSelectionMenuItems();
            if (items.Length > 0)
            {
                contextMenu.MenuItems.Add(new MenuItem("-"));
                foreach (MenuItem item in items)
                    contextMenu.MenuItems.Add(item);
            }
    
            WorkflowView workflowView = GetService(typeof(WorkflowView)) as WorkflowView;
            if (workflowView != null)
                contextMenu.Show(workflowView, workflowView.PointToClient(new Point(x, y)));
        }
    }
    

Pour créer la méthode GetSelectionMenuItems

  1. Dans la classe WorkflowMenuCommandService, créez une nouvelle méthode private nommée GetSelectionMenuItems qui retourne un tableau MenuItem.

    ' To be provided
    
    private MenuItem[] GetSelectionMenuItems()
    {
    }
    
  2. Dans la méthode GetSelectionMenuItems, créez une nouvelle collection List générique du type MenuItem et créez une nouvelle instance de cette classe.

  3. Créez une nouvelle variable Boolean locale nommée addMenuItems et initialisez-la à false.

  4. Créez une nouvelle variable ISelectionService nommée selectionService et initialisez-la en appelant la méthode GetService, passant l'objet Type de l'interface ISelectionService.

    List<MenuItem> menuItems = new List<MenuItem>();
    bool addMenuItems = true;
    
    ISelectionService selectionService = GetService(typeof(ISelectionService)) as ISelectionService;
    
  5. Créez une instruction conditionnelle qui correspond à true si le selectionService n'a pas la valeur null (Nothing en Visual Basic).

  6. Dans le bloc true de l'instruction conditionnelle créée à l'étape précédente, énumérez chaque objet Object dans la collection retournée en appelant la méthode GetSelectedComponents de l'objet selectionService.

  7. Dans le bloc d'énumérateur créé à l'étape précédente, créez une instruction conditionnelle qui correspond à true si l'objet n'est pas un objet Activity. Si la valeur est true, affectez la valeur false à la variable locale addMenuItems et créez une interruption dans le bloc d'énumérateur. Cette opération garantit que le menu contextuel n'est pas affiché si un autre objet, à l'exception de Activity, est sélectionné dans le concepteur de workflow.

    if (selectionService != null)
    {
        foreach (object obj in selectionService.GetSelectedComponents())
        {
            if (!(obj is Activity))
            {
                addMenuItems = false;
                break;
            }
        }
    }
    
  8. Créez une instruction conditionnelle qui correspond à la valeur true si la variable locale addMenuItems a la valeur true.

  9. Dans le bloc true de l'instruction conditionnelle créée à l'étape précédente, créez une nouvelle collection Dictionary générique à l'aide d'un type CommandID en tant que clé et un type String en tant que valeur, puis créez une nouvelle instance de la collection.

  10. En utilisant la table suivante comme modèle, appelez la méthode Add de la collection selectionCommands, passant un type énuméré WorkflowMenuCommands et sa valeur de chaîne affichable associée en tant que paramètres.

    Type WorkflowMenuCommands Valeur de chaîne d'interface utilisateur

    WorkflowMenuCommands.Cut

    "Cut"

    WorkflowMenuCommands.Copy

    "Copy"

    WorkflowMenuCommands.Paste

    "Paste"

    WorkflowMenuCommands.Delete

    "Delete"

    System.Workflow.ComponentModel.Design.WorkflowMenuCommands.Collapse

    "Collapse"

    System.Workflow.ComponentModel.Design.WorkflowMenuCommands.Expand

    "Expand"

    System.Workflow.ComponentModel.Design.WorkflowMenuCommands.Disable

    "Disable"

    System.Workflow.ComponentModel.Design.WorkflowMenuCommands.Enable

    "Enable"

    Dictionary<CommandID, string> selectionCommands = new Dictionary<CommandID, string>();
    selectionCommands.Add(WorkflowMenuCommands.Cut, "Cut");
    selectionCommands.Add(WorkflowMenuCommands.Copy, "Copy");
    selectionCommands.Add(WorkflowMenuCommands.Paste, "Paste");
    selectionCommands.Add(WorkflowMenuCommands.Delete, "Delete");
    selectionCommands.Add(WorkflowMenuCommands.Collapse, "Collapse");
    selectionCommands.Add(WorkflowMenuCommands.Expand, "Expand");
    selectionCommands.Add(WorkflowMenuCommands.Disable, "Disable");
    selectionCommands.Add(WorkflowMenuCommands.Enable, "Enable");
    
  11. À la suite du code créé à l'étape précédente, énumérez chaque objet CommandID dans la collection Keys de l'objet selectionCommands.

  12. Dans le bloc d'énumération créé à l'étape précédente, créez un nouvel objet MenuCommand nommé command et initialisez-le à l'aide de la méthode FindCommand, passant l'objet CommandID en tant que paramètre.

  13. Créez une nouvelle instruction conditionnelle qui correspond à true si l'objet de commande n'a pas la valeur null (Nothing en Visual Basic).

  14. Dans le bloc true de l'instruction conditionnelle créée à l'étape précédente, créez un nouvel objet MenuItem et créez une nouvelle instance, passant l'objet retourné par l'index id de la collection selectionCommands et un nouvel objet EventHandler initialisé à l'aide du délégué OnMenuClicked.

    NoteRemarque :

    La méthode déléguée OnMenuClicked sera créée dans la procédure suivante.

  15. Affectez la valeur de l'objet commandMenuCommand à la propriété Tag de l'objet menuItem que vous avez créé à l'étape précédente.

  16. Ajoutez l'objet MenuCommand command à la collection menuItems à l'aide de la méthode Add. Le code du bloc d'énumération créé dans les étapes 11-16 doit apparaître comme suit :

    foreach (CommandID id in selectionCommands.Keys)
    {
        MenuCommand command = FindCommand(id);
        if (command != null)
        {
            MenuItem menuItem = new MenuItem(selectionCommands[id], new EventHandler(OnMenuClicked));
            menuItem.Tag = command;
            menuItems.Add(menuItem);
        }
    }
    
  17. Retournez des valeurs en appelant la méthode ToArray de la collection menuItems. Le code suivant montre comment la méthode GetSelectionMenuItems doit apparaître :

    private MenuItem[] GetSelectionMenuItems()
    {
        List<MenuItem> menuItems = new List<MenuItem>();
        bool addMenuItems = true;
    
        ISelectionService selectionService = GetService(typeof(ISelectionService)) as ISelectionService;
        if (selectionService != null)
        {
            foreach (object obj in selectionService.GetSelectedComponents())
            {
                if (!(obj is Activity))
                {
                    addMenuItems = false;
                    break;
                }
            }
        }
    
        if (addMenuItems)
        {
            Dictionary<CommandID, string> selectionCommands = new Dictionary<CommandID, string>();
            selectionCommands.Add(WorkflowMenuCommands.Cut, "Cut");
            selectionCommands.Add(WorkflowMenuCommands.Copy, "Copy");
            selectionCommands.Add(WorkflowMenuCommands.Paste, "Paste");
            selectionCommands.Add(WorkflowMenuCommands.Delete, "Delete");
            selectionCommands.Add(WorkflowMenuCommands.Collapse, "Collapse");
            selectionCommands.Add(WorkflowMenuCommands.Expand, "Expand");
            selectionCommands.Add(WorkflowMenuCommands.Disable, "Disable");
            selectionCommands.Add(WorkflowMenuCommands.Enable, "Enable");
    
            foreach (CommandID id in selectionCommands.Keys)
            {
                MenuCommand command = FindCommand(id);
                if (command != null)
                {
                    MenuItem menuItem = new MenuItem(selectionCommands[id], new EventHandler(OnMenuClicked));
                    menuItem.Tag = command;
                    menuItems.Add(menuItem);
                }
            }
        }
    
        return menuItems.ToArray();
    }
    

Pour créer la méthode OnMenuClicked

  1. Dans la classe WorkflowMenuCommandService, créez une méthode private nommée OnMenuClicked qui accepte un objet Object nommé sender et un objet EventArgs nommé e en tant que paramètres.

  2. Dans la méthode OnMenuClicked, créez une nouvelle variable locale MenuItem nommée menuItem et initialisez-la en convertissant l'objet sender en un MenuItem.

  3. Créez une instruction conditionnelle qui correspond à true si le menuItem n'a pas la valeur null (Nothing en Visual Basic) et si la propriété Tag de l'objet menuItem est un objet MenuCommand.

  4. Dans le bloc true de l'instruction conditionnelle créée à l'étape précédente, convertissez menuItem.Tag property en un objet MenuCommand et appelez la méthode Invoke sur cet objet. Le code suivant montre la méthode OnMenuClicked :

    private void OnMenuClicked(object sender, EventArgs e)
    {
        MenuItem menuItem = sender as MenuItem;
        if (menuItem != null && menuItem.Tag is MenuCommand)
        {
            (menuItem.Tag as MenuCommand).Invoke();
        }
    }
    

Pour ajouter WorkflowMenuCommandService à la classe WorkflowLoader

  1. Dans la classe WorkflowLoader de Initialize après l'appel à l'implémentation de la classe de base Initialize, créez une instruction conditionnelle qui correspond à true si la propriété de classe LoaderHost n'a pas la valeur null (Nothing en Visual Basic). Le code restant de cette procédure doit être placé dans le bloc true de cette instruction conditionnelle.

  2. Dans le bloc true de l'instruction conditionnelle créée à l'étape précédente, créez une variable locale TypeProvider nommée typeProvider et créez une nouvelle instance de l'objet, passant la propriété de classe LoaderHost en tant que paramètre au constructeur.

  3. Appelez la méthode AddAssemblyReference définie dans l'objet typeProvider, passant la propriété Assembly.Location de l'objet Type pour la classe String.

  4. Appelez la méthode AddService de la propriété de classe LoaderHost, passant le Type de l'interface ITypeProvider, l'objet typeProvider et la valeur true en tant que paramètres dans la méthode.

  5. Appelez la méthode AddService de la propriété de classe LoaderHost, passant l'objet Type de l'interface IMenuCommandService et une nouvelle instance du WorkflowMenuCommandService initialisée à l'aide de la propriété LoaderHost en tant que paramètre au constructeur WorkflowMenuCommandService.

  6. La méthode Initialize complète de la classe WorkflowLoader doit apparaître comme suit :

    protected override void Initialize()
    {
        base.Initialize();
    
        if (this.LoaderHost != null)
        {
            TypeProvider typeProvider = new TypeProvider(this.LoaderHost);
            typeProvider.AddAssemblyReference(typeof(string).Assembly.Location);
    
            this.LoaderHost.AddService(typeof(ITypeProvider), typeProvider, true);
            this.LoaderHost.AddService(typeof(IMenuCommandService), new WorkflowMenuCommandService(this.LoaderHost));
        }
    }
    

Pour supprimer WorkflowMenuCommandService du WorkflowLoader

  1. Dans la classe WorkflowLoader de la méthode Dispose avant l'appel de la méthode Dispose de la classe de base, créez une instruction conditionnelle qui correspond à true si la propriété de classe LoaderHost n'a pas la valeur null (Nothing en Visual Basic).

  2. Dans le bloc true de l'instruction conditionnelle créée dans la procédure précédente, appelez la méthode RemoveService de l'objet LoaderHost, passant l'objet Type de l'interface ITypeProvider et une valeur Boolean true.

  3. Appelez la méthode RemoveService de l'objet LoaderHost, passant l'objet Type de l'interface IMenuCommandService.

  4. Le code suivant montre comment la méthode Dispose doit apparaître dans la classe WorkflowLoader.

    public override void Dispose()
    {
        if (this.LoaderHost != null)
        {
            this.LoaderHost.RemoveService(typeof(ITypeProvider), true);
            this.LoaderHost.RemoveService(typeof(IMenuCommandService));
        }
    
        base.Dispose();
    }
    

Compilation du code

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

Pour obtenir une version définitive du didacticiel, consultez Fin du didacticiel sur l'hébergement du concepteur de workflow Windows.

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.