Visual Studio Extensions and Menu Subitems

Posted on | 512 words | ~3 mins

Recently I was working on a Visual Studio Extension for VS2010, instead of a single item in the the tools menu, what I wanted was a single item with a set of child items.

Strangely enough, documentation on this is quite lacking. So if you need to know how to do it, here's the gist. First, create a standard Visual Studio 2010 extension with the wizard, we'll have some code like the below to start off with, in the OnConnection function:

object []contextGUIDS = new object[] { };
Commands2 commands = (Commands2)_applicationObject.Commands;
string toolsMenuName = "Tools";

//Place the command on the tools menu.
//Find the MenuBar command bar, which is the top-level command bar holding all the main menu items:
Microsoft.VisualStudio.CommandBars.CommandBar menuBarCommandBar = ((Microsoft.VisualStudio.CommandBars.CommandBars)_applicationObject.CommandBars)["MenuBar"];

//Find the Tools command bar on the MenuBar command bar:
CommandBarControl toolsControl = menuBarCommandBar.Controls[toolsMenuName];
CommandBarPopup toolsPopup = (CommandBarPopup)toolsControl;

//This try/catch block can be duplicated if you wish to add multiple commands to be handled by your Add-in,
//  just make sure you also update the QueryStatus/Exec method to include the new command names.
try
{
	//Add a command to the Commands collection:
    Command command = commands.AddNamedCommand2(_addInInstance, "MyCommand", "MyCommand",
        "Executes the command for MyCommand", true, 59, ref contextGUIDS,
        (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled,
        (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton);

   	//Add a control for the command to the tools menu:
	if((command != null) && (toolsPopup != null))
	{
		command.AddControl(toolsPopup.CommandBar, 1);
	}
}
catch(System.ArgumentException)
{
	//If we are here, then the exception is probably because a command with that name
	//  already exists. If so there is no need to recreate the command and we can
    //  safely ignore the exception.
}

Now what we're going to do first, is change the code so that we don't actually add a Command named MyCommand, but instead a popup:

//This try/catch block can be duplicated if you wish to add multiple commands to be handled by your Add-in,
//  just make sure you also update the QueryStatus/Exec method to include the new command names.
try
{
	//  Have we got the tools popup?
	if(toolsPopup != null)
	{
        //  Create 'MyCommand' as a popup.
        var popup = (CommandBarPopup)toolsPopup.Controls.Add(MsoControlType.msoControlPopup);
        popup.Caption = "MyCommand";
	}
}
catch(System.ArgumentException)
{
	//If we are here, then the exception is probably because a command with that name<br />
	//  already exists. If so there is no need to recreate the command and we can<br />
    //  safely ignore the exception.
}

Now that we have the popup object, we can create commands and add them to the popup instead:

//  Have we got the tools popup?
if(toolsPopup != null)
{
    //  Create 'MyCommand' as a popup.
    var popup = (CommandBarPopup)toolsPopup.Controls.Add(MsoControlType.msoControlPopup);
    popup.Caption = "MyCommand";
    //  Create sub item 1.
    var subItem1Command = commands.AddNamedCommand2(_addInInstance, "MyCommand1", "My Command Subitem 1", "My Command Subitem 1",
                                                       true, 59, ref contextGUIDS);
    //  Add it.
    subItem1Command.AddControl(popup.CommandBar, 1);
    //  Create sub item 2.
    var subItem2Command = commands.AddNamedCommand2(_addInInstance, "MyCommand2", "My Command Subitem 2", "My Command Subitem 2",
                                                       true, 59, ref contextGUIDS);
    //  Add it.
    subItem2Command.AddControl(popup.CommandBar, 2);
}

Now that we have made these changes, if we run the addin, we get a menu structure like this: