Walkthrough: Adding a Menu Controller to a Toolbar

This walkthrough builds on the Adding a Toolbar to a Tool Window walkthrough and shows how to add a menu controller to the tool window toolbar. The steps shown here also can be applied to the toolbar that is created in the walkthrough, Adding a Toolbar to the IDE.

A menu controller is a split control. The left side of the menu controller shows the last-used command, and it can be run by clicking it. The right side of the menu controller is an arrow that, when clicked, opens a list of additional commands. When you click a command on the list, the command runs, and it replaces the command on the left side of the menu controller. In this way, the menu controller operates like a command button that always shows the last-used command from a list.

Menu controllers can appear on menus but they are most often used on toolbars.

This walkthrough demonstrates a menu controller that offers three selectable options, which are defined in the .vsct file. For more information about menus and .vsct files, see Commands, Menus, and Toolbars.

Prerequisites

To complete this walkthrough, you must install the Visual Studio 2010 SDK.

Note

For more information about the Visual Studio SDK, see Extending Visual Studio Overview. To find out how to download the Visual Studio SDK, see Visual Studio Extensibility Developer Center on the MSDN Web site.

Creating a Menu Controller

To create a menu controller

  1. Follow the procedures described in Walkthrough: Adding a Toolbar to a Tool Window to create a tool window VSPackage that has a toolbar.

  2. In Solution Explorer, double-click TWToolbar.vsct to open it in a text editor.

  3. In the Symbols section, in the GuidSymbol element named "guidTWToolbarCmdSet", declare your menu controller, menu controller group, and three menu items.

    <IDSymbol name="TestMenuController" value="0x1300"/>
    <IDSymbol name="TestMenuControllerGroup" value="0x1060"/>
    <IDSymbol name="cmdidMCItem1" value="0x0130"/>
    <IDSymbol name="cmdidMCItem2" value="0x0131"/>
    <IDSymbol name="cmdidMCItem3" value="0x0132"/>
    
  4. In the Menus section, after the last menu entry, define the menu controller as a menu.

    <Menu guid="guidTWToolbarCmdSet" id="TestMenuController"
          priority="0x0100" type="MenuController">
      <Parent guid="guidTWToolbarCmdSet" id="TWToolbarGroup"/>
      <CommandFlag>IconAndText</CommandFlag>
      <CommandFlag>TextChanges</CommandFlag>
      <CommandFlag>TextIsAnchorCommand</CommandFlag>
      <Strings>
        <ButtonText>Test Menu Controller</ButtonText>
        <CommandName>Test Menu Controller</CommandName>
      </Strings>
    </Menu>
    

    The TextChanges and TextIsAnchorCommand flags must be included to enable the menu controller to reflect the last selected command.

  5. In the Groups section, after the last group entry, add the menu controller group.

    <Group guid="guidTWToolbarCmdSet" id="TestMenuControllerGroup"
          priority="0x000">
      <Parent guid="guidTWToolbarCmdSet" id="TestMenuController"/>
    </Group>
    

    By setting the menu controller as the parent, any commands placed in this group will appear in the menu controller. The priority attribute is omitted, which sets it to the default value of 0, because it will be the only group on the menu controller.

  6. In the Buttons section, after the last button entry, add a Button element for each of your menu items.

    <Button guid="guidTWToolbarCmdSet" id="cmdidMCItem1"
          priority="0x0000" type="Button">
      <Parent guid="guidTWToolbarCmdSet" id="TestMenuControllerGroup"/>
      <Icon guid="guidTWToolbarCmdSet" id="bmpPic1"/>
      <CommandFlag>IconAndText</CommandFlag>
      <Strings>
        <ButtonText>MC Item 1</ButtonText>
        <CommandName>MC Item 1</CommandName>
      </Strings>
    </Button>
    <Button guid="guidTWToolbarCmdSet" id="cmdidMCItem2"
          priority="0x0100" type="Button">
      <Parent guid="guidTWToolbarCmdSet" id="TestMenuControllerGroup"/>
      <Icon guid="guidTWToolbarCmdSet" id="bmpPic2"/>
      <CommandFlag>IconAndText</CommandFlag>
      <Strings>
        <ButtonText>MC Item 2</ButtonText>
        <CommandName>MC Item 2</CommandName>
      </Strings>
    </Button>
    <Button guid="guidTWToolbarCmdSet" id="cmdidMCItem3"
          priority="0x0200" type="Button">
      <Parent guid="guidTWToolbarCmdSet" id="TestMenuControllerGroup"/>
      <Icon guid="guidTWToolbarCmdSet" id="bmpPicSmile"/>
      <CommandFlag>IconAndText</CommandFlag>
      <Strings>
        <ButtonText>MC Item 3</ButtonText>
        <CommandName>MC Item 3</CommandName>
      </Strings>
    </Button>
    
  7. At this point, you can look at the menu controller.

    1. Press F5to open an instance of the experimental Visual Studio.

    2. On the View menu, point to Other Windows, and then click Test Tool Window.

    3. The menu controller appears on the toolbar in the tool window.

    4. Click the arrow on the right-hand side of the menu controller to see the three possible commands.

    Notice that when you click a command, the left-hand side of the menu controller changes to display that command. In the next section, we will add the code to activate these commands.

  8. Close the experimental Visual Studio.

Implementing the Menu Controller Commands

To implement the menu controller commands in managed code

  1. In Solution Explorer, double-click PkgCmdID.cs to open it in a text editor.

  2. After the existing command IDs in the PkgCmdIDList class, add command IDs for your three menu items.

    public const int cmdidMCItem1 = 0x130;
    public const int cmdidMCItem2 = 0x131;
    public const int cmdidMCItem3 = 0x132;
    
  3. In Solution Explorer, open TWToolbarPackage.cs.

  4. At the top of the TWToolbarPackage class, add the following:

    private int currentMCCommand; // The currently selected menu controller command
    
  5. Locate the hidden region labeled "Package Members" and expand it by clicking the plus sign in the left margin.

  6. In the Initialize method, immediately after the last call to the AddCommand method, add code to route the events for each command through the same handlers.

    for (int i = PkgCmdIDList.cmdidMCItem1; i <=
        PkgCmdIDList.cmdidMCItem3; i++)
    {
        CommandID cmdID = new
        CommandID(GuidList.guidTWToolbarCmdSet, i);
        OleMenuCommand mc = new OleMenuCommand(new
          EventHandler(OnMCItemClicked), cmdID);
        mc.BeforeQueryStatus += new EventHandler(OnMCItemQueryStatus);
        mcs.AddCommand(mc);
        // The first item is, by default, checked.
        if (PkgCmdIDList.cmdidMCItem1 == i)
        {
            mc.Checked = true;
            this.currentMCCommand = i;
        }
    }
    
  7. At the end of the TWToolbarPackage class, right after the MenuItemCallback method, add a method to mark the selected command as checked.

    private void OnMCItemQueryStatus(object sender, EventArgs e)
    {
        OleMenuCommand mc = sender as OleMenuCommand;
        if (null != mc)
        {
            mc.Checked = (mc.CommandID.ID == this.currentMCCommand);
        }
    }
    
  8. After the OnMCItemQueryStatus method, add an event handler for when the user selects a command on the menu controller:

    private void OnMCItemClicked(object sender, EventArgs e)
    {
        OleMenuCommand mc = sender as OleMenuCommand;
        if (null != mc)
        {
            string selection;
            switch (mc.CommandID.ID)
            {
                case PkgCmdIDList.cmdidMCItem1:
                    selection = "Menu controller Item 1";
                    break;
    
                case PkgCmdIDList.cmdidMCItem2:
                    selection = "Menu controller Item 2";
                    break;
    
                case PkgCmdIDList.cmdidMCItem3:
                    selection = "Menu controller Item 3";
                    break;
    
                default:
                    selection = "Unknown command";
                    break;
            }
            this.currentMCCommand = mc.CommandID.ID;
    
            IVsUIShell uiShell =
              (IVsUIShell)GetService(typeof(SVsUIShell));
            Guid clsid = Guid.Empty;
            int result;
            uiShell.ShowMessageBox(
                       0,
                       ref clsid,
                       "Test Tool Window Toolbar Package",
                       string.Format(CultureInfo.CurrentCulture,
                                     "You selected {0}", selection),
                       string.Empty,
                       0,
                       OLEMSGBUTTON.OLEMSGBUTTON_OK,
                       OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST,
                       OLEMSGICON.OLEMSGICON_INFO,
                       0,
                       out result);
        }
    }
    
  9. Build the solution, and correct any errors that occur.

Testing the Menu Controller

To test the menu controller

  1. Press F5 to open an instance of the experimental Visual Studio.

  2. Open the Test Tool Window.

    The menu controller appears in the toolbar in the tool window and displays "MC Item 1".

  3. Click the menu controller button to the left of the arrow.

    A dialog box appears and displays the message "Selected Menu controller Item 1". Notice that the message corresponds to the text on the menu controller button.

  4. Click the arrow on the menu controller to display three items, the first of which is selected and has a highlight box around its icon. Click MC Item 3.

    A dialog box appears and displays the message "Selected Menu controller Item 3". The menu controller button now displays "MC Item 3".

  5. Click the arrow on the menu controller to display the options. Notice that the new default, MC Item 3, now is selected.

See Also

Tasks

Walkthrough: Adding a Toolbar to a Tool Window

Walkthrough: Adding a Toolbar to the IDE

Other Resources

Walkthroughs for Commands, Menus, and Toolbars

Commands, Menus, and Toolbars