Ajouter dynamiquement des éléments de MenuDynamically Adding Menu Items

Vous pouvez ajouter des éléments de menu au moment de l’exécution en spécifiant le DynamicItemStart commande indicateur sur une définition de bouton d’espace réservé dans le fichier de commandes-table (.vsct) de Visual Studio, puis définir (dans le code), le nombre de menu d’éléments à afficher et gérer les commandes.You can add menu items at run time by specifying the DynamicItemStart command flag on a placeholder button definition in the Visual Studio command-table (.vsct) file, then defining (in code) the number of menu items to display and handling the command(s). Lorsque le VSPackage est chargé, l’espace réservé est remplacé par les éléments de menu dynamique.When the VSPackage is loaded, the placeholder is replaced with the dynamic menu items.

Visual Studio utilise des listes dynamiques dans le des derniers fichiers utilisés liste (MRU), qui affiche les noms de documents qui ont été ouverts récemment, et le Windows liste, qui affiche les noms de windows qui sont actuellement ouverts.Visual Studio uses dynamic lists in the Most Recently Used (MRU) list, which displays the names of documents that have been opened recently, and the Windows list, which displays the names of windows that are currently open. Le DynamicItemStart indicateur sur une définition de commande indique que la commande est un espace réservé jusqu'à ce que le VSPackage est ouvert.The DynamicItemStart flag on a command definition specifies that the command is a placeholder until the VSPackage is opened. Lorsque le VSPackage est ouverte, l’espace réservé est remplacé par 0 ou plusieurs commandes qui sont créés au moment de l’exécution et ajoutés à la liste dynamique.When the VSPackage is opened, the placeholder is replaced with 0 or more commands that are created at run time and added to the dynamic list. Vous n’êtes peut-être pas en mesure d’afficher la position dans le menu dans lequel la liste dynamique s’affiche jusqu'à ce que le VSPackage est ouvert.You may not be able to see the position on the menu where the dynamic list appears until the VSPackage is opened. Pour remplir une liste dynamique, Visual Studio vous demande le VSPackage pour rechercher une commande avec un ID dont les premiers caractères sont les mêmes que l’ID de l’espace réservé.To populate the dynamic list, Visual Studio asks the VSPackage to look for a command with an ID whose first characters are the same as the ID of the placeholder. Lorsque Visual Studio détecte une commande, il ajoute le nom de la commande à la liste dynamique.When Visual Studio finds a matching command, it adds the name of the command to the dynamic list. Ensuite, elle incrémente l’ID et recherche d’une autre commande correspondante à ajouter à la liste dynamique jusqu'à ce qu’il n’y a plus dynamiques commandes.Then it increments the ID and looks for another matching command to add to the dynamic list until there are no more dynamic commands.

Cette procédure pas à pas montre comment définir le projet de démarrage dans une solution Visual Studio avec une commande sur le l’Explorateur de solutions barre d’outils.This walkthrough shows how to set the startup project in a Visual Studio solution with a command on the Solution Explorer toolbar. Elle utilise un contrôleur de menu qui a une liste dynamique des projets de la solution active.It uses a menu controller that has a dynamic dropdown list of the projects in the active solution. Pour éviter que cette commande qui s’affiche lorsqu’aucune solution n’est ouverte, ou lorsque la solution ouverte n'a qu’un seul projet, le VSPackage est chargé uniquement quand une solution comporte plusieurs projets.To keep this command from appearing when no solution is open or when the open solution has only one project, the VSPackage is loaded only when a solution has multiple projects.

Pour plus d’informations sur les fichiers .vsct, consultez Visual Studio Command Table (. Fichiers VSCT).For more information about .vsct files, see Visual Studio Command Table (.Vsct) Files.

Création d’une Extension avec une commande de MenuCreating an Extension with a Menu Command

  1. Créez un projet VSIX nommé DynamicMenuItems.Create a VSIX project named DynamicMenuItems.

  2. Lorsque le projet s’ouvre, ajouter un modèle d’élément de commande personnalisée et nommez-le DynamicMenu.When the project opens, add a custom command item template and name it DynamicMenu. Pour plus d’informations, consultez avec une commande de Menu pour créer une Extension.For more information, see Creating an Extension with a Menu Command.

Les éléments de configuration dans le fichier .vsctSetting up the elements in the .vsct file

Pour créer un contrôleur de menu avec des éléments de menu dynamiques dans une barre d’outils, vous spécifiez les éléments suivants :To create a menu controller with dynamic menu items on a toolbar, you specify the following elements:

  • Deux groupes, celui qui contient le contrôleur de menu et une autre qui contient les éléments de menu dans la liste déroulante de commandeTwo command groups, one that contains the menu controller and another that contains the menu items in the dropdown

  • Un élément de menu de type MenuControllerOne menu element of type MenuController

  • Deux boutons, qui agit comme l’espace réservé pour les éléments de menu et l’autre qui fournit l’icône et l’info-bulle dans la barre d’outils.Two buttons, one that acts as the placeholder for the menu items and another that supplies the icon and the tooltip on the toolbar.

  1. Dans DynamicMenuPackage.vsct, définissez les ID de commande.In DynamicMenuPackage.vsct, define the command IDs. Accédez à la section de symboles et remplacez les éléments IDSymbol dans les guidDynamicMenuPackageCmdSet GuidSymbol bloc.Go to the Symbols section and replace the IDSymbol elements in the guidDynamicMenuPackageCmdSet GuidSymbol block. Vous devez définir les éléments de IDSymbol pour les deux groupes, le contrôleur de menu, la commande de l’espace réservé et la commande d’ancre.You need to define IDSymbol elements for the two groups, the menu controller, the placeholder command, and the anchor command.

    <GuidSymbol name="guidDynamicMenuPackageCmdSet" value="{ your GUID here }">  
        <IDSymbol name="MyToolbarItemGroup" value="0x1020" />  
        <IDSymbol name="MyMenuControllerGroup" value="0x1025" />  
        <IDSymbol name="MyMenuController" value ="0x1030"/>  
        <IDSymbol name="cmdidMyAnchorCommand" value="0x0103" />  
        <!-- NOTE: The following command expands at run time to some number of ids.  
         Try not to place command ids after it (e.g. 0x0105, 0x0106).  
         If you must add a command id after it, make the gap very large (e.g. 0x200) -->  
        <IDSymbol name="cmdidMyDynamicStartCommand" value="0x0104" />  
    </GuidSymbol>    
    
  2. Dans la section groupes, supprimez les groupes existants et ajouter les deux groupes que vous venez de définir :In the Groups section, delete the existing groups and add the two groups you just defined:

    <Groups>  
        <!-- The group that adds the MenuController on the Solution Explorer toolbar.   
             The 0x4000 priority adds this group after the group that contains the  
             Preview Selected Items button, which is normally at the far right of the toolbar. -->  
        <Group guid="guidDynamicMenuPackageCmdSet" id="MyToolbarItemGroup" priority="0x4000" >  
            <Parent guid="guidSHLMainMenu" id="IDM_VS_TOOL_PROJWIN" />  
        </Group>  
        <!-- The group for the items on the MenuController drop-down. It is added to the MenuController submenu. -->  
        <Group guid="guidDynamicMenuPackageCmdSet" id="MyMenuControllerGroup" priority="0x4000" >  
            <Parent guid="guidDynamicMenuPackageCmdSet" id="MyMenuController" />  
        </Group>  
    </Groups>  
    

    Ajoutez le MenuController.Add the MenuController. Définissez l’indicateur de commande DynamicVisibility, car il n’est pas toujours visible.Set the DynamicVisibility command flag, since it is not always visible. Le ButtonText n’est pas affichée.The ButtonText is not displayed.

    <Menus>  
        <!-- The MenuController to display on the Solution Explorer toolbar.  
             Place it in the ToolbarItemGroup.-->  
        <Menu guid="guidDynamicMenuPackageCmdSet" id="MyMenuController" priority="0x1000" type="MenuController">  
            <Parent guid="guidDynamicMenuPackageCmdSet" id="MyToolbarItemGroup" />  
            <CommandFlag>DynamicVisibility</CommandFlag>  
            <Strings>  
               <ButtonText></ButtonText>  
           </Strings>  
        </Menu>  
    </Menus>  
    
  3. Ajoutez deux boutons, un espace réservé pour les éléments de menu dynamique et l’autre comme un point d’ancrage pour le MenuController.Add two buttons, one as a placeholder for the dynamic menu items and one as an anchor for the MenuController.

    Le parent du bouton espace réservé est la MyMenuControllerGroup.The parent of the placeholder button is the MyMenuControllerGroup. Ajoutez les indicateurs de commande DynamicItemStart, DynamicVisibility et TextChanges au bouton espace réservé.Add the DynamicItemStart, DynamicVisibility, and TextChanges command flags to the placeholder button. Le ButtonText n’est pas affichée.The ButtonText is not displayed.

    Le bouton d’ancrage conserve l’icône et le texte d’info-bulle.The anchor button holds the icon and the tooltip text. Le parent du bouton d’ancrage est également le MyMenuControllerGroup.The parent of the anchor button is also the MyMenuControllerGroup. Vous ajoutez l’indicateur de commande NoShowOnMenuController pour vous assurer que le bouton n’apparaît pas réellement dans le menu déroulant de contrôleur et l’indicateur de commande FixMenuController afin de faciliter l’ancre permanente.You add the NoShowOnMenuController command flag to make sure the button doesn't actually appear in the menu controller dropdown, and the FixMenuController command flag to make it the permanent anchor.

    <!-- The placeholder for the dynamic items that expand to N items at runtime. -->  
    <Buttons>  
        <Button guid="guidDynamicMenuPackageCmdSet" id="cmdidMyDynamicStartCommand" priority="0x1000" >  
          <Parent guid="guidDynamicMenuPackageCmdSet" id="MyMenuControllerGroup" />  
          <CommandFlag>DynamicItemStart</CommandFlag>  
          <CommandFlag>DynamicVisibility</CommandFlag>  
          <CommandFlag>TextChanges</CommandFlag>  
          <!-- This text does not appear. -->  
          <Strings>  
            <ButtonText>Project</ButtonText>  
          </Strings>  
        </Button>  
    
        <!-- The anchor item to supply the icon/tooltip for the MenuController -->  
        <Button guid="guidDynamicMenuPackageCmdSet" id="cmdidMyAnchorCommand" priority="0x0000" >  
          <Parent guid="guidDynamicMenuPackageCmdSet" id="MyMenuControllerGroup" />  
          <!-- This is the icon that appears on the Solution Explorer toolbar. -->  
          <Icon guid="guidImages" id="bmpPicArrows"/>  
          <!-- Do not show on the menu controller's drop down list-->  
          <CommandFlag>NoShowOnMenuController</CommandFlag>  
          <!-- Become the permanent anchor item for the menu controller -->  
          <CommandFlag>FixMenuController</CommandFlag>  
          <!-- The text that appears in the tooltip.-->  
          <Strings>  
            <ButtonText>Set Startup Project</ButtonText>  
          </Strings>  
        </Button>  
    </Buttons>  
    
  4. Ajouter une icône au projet (dans le dossier de ressources), puis ajoutez la référence à celle-ci dans le fichier .vsct.Add an icon to the project (in the Resources folder), and then add the reference to it in the .vsct file. Dans cette procédure pas à pas, nous utilisons l’icône de flèches qui est inclus dans le modèle de projet.In this walkthrough, we use the Arrows icon that's included in the project template.

  5. Ajoutez une section VisibilityConstraints en dehors de la section commandes juste avant la section de symboles.Add a VisibilityConstraints section outside the Commands section just before the Symbols section. (Vous pouvez obtenir un avertissement si vous l’ajoutez après les symboles). Cette section permet de s’assurer que le contrôleur de menu s’affiche uniquement quand une solution avec plusieurs projets est chargée.(You may get a warning if you add it after Symbols.) This section makes sure that the menu controller appears only when a solution with multiple projects is loaded.

    <VisibilityConstraints>  
         <!--Make the MenuController show up only when there is a solution with more than one project loaded-->  
        <VisibilityItem guid="guidDynamicMenuPackageCmdSet" id="MyMenuController" context="UICONTEXT_SolutionHasMultipleProjects"/>  
    </VisibilityConstraints>  
    

Implémentation de la commande de menu dynamiqueImplementing the dynamic menu command

Vous créez une classe de commande de menu dynamique qui hérite de OleMenuCommand.You create a dynamic menu command class that inherits from OleMenuCommand. Dans cette implémentation, le constructeur spécifie un prédicat à utiliser pour la correspondance des commandes.In this implementation, the constructor specifies a predicate to be used for matching commands. Vous devez substituer la DynamicItemMatch méthode à utiliser ce prédicat pour définir le MatchedCommandId propriété, qui identifie la commande à appeler.You must override the DynamicItemMatch method to use this predicate to set the MatchedCommandId property, which identifies the command to be invoked.

  1. Créer un nouveau fichier de classe c# nommé DynamicItemMenuCommand.cs et ajoutez une classe nommée DynamicItemMenuCommand qui hérite de OleMenuCommand:Create a new C# class file named DynamicItemMenuCommand.cs, and add a class named DynamicItemMenuCommand that inherits from OleMenuCommand:

    class DynamicItemMenuCommand : OleMenuCommand  
    {  
    
    }  
    
  2. Ajoutez le code suivant à l’aide des instructions :Add the following using statements:

    using Microsoft.VisualStudio.Shell;  
    using Microsoft.VisualStudio.Shell.Interop;  
    using System.ComponentModel.Design;  
    
  3. Ajoutez un champ privé pour stocker le prédicat de correspondance :Add a private field to store the match predicate:

    private Predicate<int> matches;  
    
  4. Ajoutez un constructeur qui hérite de la OleMenuCommand constructeur et spécifie un gestionnaire de commandes et un BeforeQueryStatus gestionnaire.Add a constructor that inherits from the OleMenuCommand constructor and specifies a command handler and a BeforeQueryStatus handler. Ajouter un prédicat pour la correspondance de la commande :Add a predicate for matching the command:

    public DynamicItemMenuCommand(CommandID rootId, Predicate<int> matches, EventHandler invokeHandler, EventHandler beforeQueryStatusHandler)  
        : base(invokeHandler, null /*changeHandler*/, beforeQueryStatusHandler, rootId)  
    {  
        if (matches == null)  
        {  
            throw new ArgumentNullException("matches");  
        }  
    
        this.matches = matches;  
    }  
    
  5. Remplacer la DynamicItemMatch méthode afin qu’il appelle les correspondances de prédicat et définit le MatchedCommandId propriété :Override the DynamicItemMatch method so that it calls the matches predicate and sets the MatchedCommandId property:

    public override bool DynamicItemMatch(int cmdId)  
    {  
        // Call the supplied predicate to test whether the given cmdId is a match.  
        // If it is, store the command id in MatchedCommandid   
        // for use by any BeforeQueryStatus handlers, and then return that it is a match.  
        // Otherwise clear any previously stored matched cmdId and return that it is not a match.  
        if (this.matches(cmdId))  
        {  
            this.MatchedCommandId = cmdId;  
            return true;  
        }  
    
        this.MatchedCommandId = 0;  
        return false;  
    }  
    

Ajout de la commandeAdding the command

Le constructeur de DynamicMenu est où vous configurez des commandes de menu, y compris les menus dynamiques et des éléments de menu.The DynamicMenu constructor is where you set up menu commands, including dynamic menus and menu items.

  1. Dans DynamicMenuPackage.cs, ajoutez le GUID du jeu de commandes et l’ID de commande :In DynamicMenuPackage.cs, add the GUID of the command set and the command ID:

    public const string guidDynamicMenuPackageCmdSet = "00000000-0000-0000-0000-00000000";  // get the GUID from the .vsct file  
    public const uint cmdidMyCommand = 0x104;  
    
  2. Dans le fichier DynamicMenu.cs, ajoutez le code suivant à l’aide des instructions :In the DynamicMenu.cs file, add the following using statements:

    using EnvDTE;  
    using EnvDTE80;  
    using System.ComponentModel.Design;  
    
  3. Dans la classe de schéma, ajoutez un champ privé dte2.In the DynamicMenu class, add a private field dte2.

    private DTE2 dte2;  
    
  4. Ajouter un champ privé rootItemId :Add a private rootItemId field:

    private int rootItemId = 0;  
    
  5. Dans le constructeur de DynamicMenu, ajoutez la commande de menu.In the DynamicMenu constructor, add the menu command. Dans la section suivante, nous allons définir le Gestionnaire de commandes, le BeforeQueryStatus Gestionnaire d’événements et le prédicat de correspondance.In the next section we'll define the command handler, the BeforeQueryStatus event handler, and the match predicate.

    private DynamicMenu(Package package)  
    {  
        if (package == null)  
        {  
            throw new ArgumentNullException(nameof(package));  
        }  
    
        this.package = package;  
    
        OleMenuCommandService commandService = this.ServiceProvider.GetService(typeof(IMenuCommandService)) as OleMenuCommandService;  
        if (commandService != null)  
        {  
            // Add the DynamicItemMenuCommand for the expansion of the root item into N items at run time.   
            CommandID dynamicItemRootId = new CommandID(new Guid(DynamicMenuPackageGuids.guidDynamicMenuPackageCmdSet), (int)DynamicMenuPackageGuids.cmdidMyCommand);  
            DynamicItemMenuCommand dynamicMenuCommand = new DynamicItemMenuCommand(dynamicItemRootId,  
                IsValidDynamicItem,  
                OnInvokedDynamicItem,  
                OnBeforeQueryStatusDynamicItem);  
                commandService.AddCommand(dynamicMenuCommand);  
                }  
    
        dte2 = (DTE2)this.ServiceProvider.GetService(typeof(DTE));  
    }  
    

Les gestionnaires de mise en œuvreImplementing the handlers

Pour implémenter des éléments de menu dynamique sur un contrôleur de menu, vous devez gérer la commande lorsque l’utilisateur clique sur un élément dynamique.To implement dynamic menu items on a menu controller, you must handle the command when a dynamic item is clicked. Vous devez également implémenter la logique qui définit l’état de l’élément de menu.You must also implement the logic that sets the state of the menu item. Ajouter les gestionnaires à la classe de schéma.Add the handlers to the DynamicMenu class.

  1. Pour implémenter le définir un projet de démarrage de commande, ajoutez le OnInvokedDynamicItem Gestionnaire d’événements.To implement the Set Startup Project command, add the OnInvokedDynamicItem event handler. Il recherche le projet dont le nom est le même que le texte de la commande qui a été appelée et la définit comme projet de démarrage en définissant son chemin d’accès absolu dans le StartupProjects propriété.It looks for the project whose name is the same as the text of the command that has been invoked, and sets it as the startup project by setting its absolute path in the StartupProjects property.

    private void OnInvokedDynamicItem(object sender, EventArgs args)  
    {  
        DynamicItemMenuCommand invokedCommand = (DynamicItemMenuCommand)sender;  
        // If the command is already checked, we don't need to do anything  
        if (invokedCommand.Checked)  
            return;  
    
        // Find the project that corresponds to the command text and set it as the startup project  
        var projects = dte2.Solution.Projects;  
        foreach (Project proj in projects)  
        {  
            if (invokedCommand.Text.Equals(proj.Name))  
            {  
                dte2.Solution.SolutionBuild.StartupProjects = proj.FullName;  
                return;  
            }  
        }  
    }  
    
  2. Ajouter le OnBeforeQueryStatusDynamicItem Gestionnaire d’événements.Add the OnBeforeQueryStatusDynamicItem event handler. Il s’agit du gestionnaire appelé avant une QueryStatus événement.This is the handler called before a QueryStatus event. Il détermine si l’élément de menu est un élément « real », autrement dit, pas l’élément d’espace réservé, et indique si l’élément est déjà activé (ce qui signifie que le projet est déjà défini comme projet de démarrage).It determines whether the menu item is a "real" item, that is, not the placeholder item, and whether the item is already checked (meaning that the project is already set as the startup project).

    private void OnBeforeQueryStatusDynamicItem(object sender, EventArgs args)  
    {  
        DynamicItemMenuCommand matchedCommand = (DynamicItemMenuCommand)sender;  
        matchedCommand.Enabled = true;  
        matchedCommand.Visible = true;  
    
        // Find out whether the command ID is 0, which is the ID of the root item.  
        // If it is the root item, it matches the constructed DynamicItemMenuCommand,  
         // and IsValidDynamicItem won't be called.  
        bool isRootItem = (matchedCommand.MatchedCommandId == 0);  
    
        // The index is set to 1 rather than 0 because the Solution.Projects collection is 1-based.  
        int indexForDisplay = (isRootItem ? 1 : (matchedCommand.MatchedCommandId - (int) DynamicMenuPackageGuids.cmdidMyCommand) + 1);  
    
        matchedCommand.Text = dte2.Solution.Projects.Item(indexForDisplay).Name;  
    
        Array startupProjects = (Array)dte2.Solution.SolutionBuild.StartupProjects;  
        string startupProject = System.IO.Path.GetFileNameWithoutExtension((string)startupProjects.GetValue(0));  
    
        // Check the command if it isn't checked already selected  
        matchedCommand.Checked = (matchedCommand.Text == startupProject);  
    
        // Clear the ID because we are done with this item.  
        matchedCommand.MatchedCommandId = 0;  
    }  
    

Mise en œuvre le prédicat de correspondance d’ID commandeImplementing the command ID match predicate

  1. Désormais implémenter le prédicat de correspondance.Now implement the match predicate. Nous devons déterminer deux choses : tout d’abord, si l’ID de commande est valide (il est supérieur ou égal à l’ID de commande déclaré) et le second, si elle spécifie un projet (il est inférieur au nombre de projets dans la solution).We need to determine two things: first, whether the command ID is valid (it is greater than or equal to the declared command ID), and second, whether it specifies a possible project (it is less than the number of projects in the solution).

    private bool IsValidDynamicItem(int commandId)  
    {  
        // The match is valid if the command ID is >= the id of our root dynamic start item   
        // and the command ID minus the ID of our root dynamic start item  
        // is less than or equal to the number of projects in the solution.  
        return (commandId >= (int)DynamicMenuPackageGuids.cmdidMyCommand) && ((commandId - (int)DynamicMenuPackageGuids.cmdidMyCommand) < dte2.Solution.Projects.Count);  
    }  
    

Définir le VSPackage pour charger uniquement quand une solution comporte plusieurs projetsSetting the VSPackage to load only when a solution has multiple projects

Étant donné que la définir un projet de démarrage commande n’a aucune signification, sauf si la solution active comporte plusieurs projets, vous pouvez définir votre VSPackage pour charger automatiquement que dans ce cas.Because the Set Startup Project command doesn't make sense unless the active solution has more than one project, you can set your VSPackage to auto-load only in that case. Vous utilisez ProvideAutoLoadAttribute ainsi que le contexte de l’interface utilisateur SolutionHasMultipleProjects.You use ProvideAutoLoadAttribute together with the UI context SolutionHasMultipleProjects. Dans le fichier DynamicMenuPackage.cs ajouter les attributs suivants à la classe DynamicMenuPackage :In the DynamicMenuPackage.cs file add the following attributes to the DynamicMenuPackage class:

[PackageRegistration(UseManagedResourcesOnly = true)]  
[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]  
[ProvideMenuResource("Menus.ctmenu", 1)]  
[ProvideAutoLoad(UIContextGuids.SolutionHasMultipleProjects)]  
[Guid(DynamicMenuPackage.PackageGuidString)]  
public sealed class DynamicMenuItemsPackage : Package  
{}  

Test de la commande de définir un projet de démarrageTesting the Set Startup Project command

Vous pouvez maintenant tester votre code.Now you can test your code.

  1. Générez le projet et commencez le débogage.Build the project and start debugging. L’instance expérimentale doit apparaître.The experimental instance should appear.

  2. Dans l’instance expérimentale, ouvrez une solution qui contient plusieurs projets.In the experimental instance, open a solution that has more than one project.

    Vous devez voir l’icône de flèche sur la l’Explorateur de solutions barre d’outils.You should see the arrow icon on the Solution Explorer toolbar. Lorsque vous le développez, les éléments de menu qui représentent les différents projets dans la solution doivent apparaître.When you expand it, menu items that represent the different projects in the solution should appear.

  3. Lorsque vous activez un des projets, il devienne le projet de démarrage.When you check one of the projects, it becomes the startup project.

  4. Lorsque vous fermez la solution, ou que vous ouvrez une solution qui contient un seul projet, la barre d’outils doit disparaître.When you close the solution, or open a solution that has only one project, the toolbar icon should disappear.

Voir aussiSee Also

Commandes, Menus et barres d’outils Commands, Menus, and Toolbars
Comment VSPackages ajoute des éléments de l’interface utilisateurHow VSPackages Add User Interface Elements