In Part #14 I showed you the basics of the .vsct file. In that article I focused on creating very simple menus and promised to go on with advanced concepts. Well, I voluntarily interrupted discovering menus and VSCT stuff for the sake of custom editors. Now I returned to this topic again.
Before going again into the structure of .vsct files I would like to turn your attention to David DeWinter’s blog. David wrote two great articles on creating dynamic menus in VS. You can find them here: Part #1 and Part #2.
Since it was a few weeks ago when I published Part #14, please go back I read the article again (or just “cache” it) to be in context.
Creating submenus
In Part #14 treating the .vsct basics I showed you a few samples. Here we start from a sample introduced there:
This sample has four commands divided into two logical groups. The related .vsct is the following:
<?xml version="1.0" encoding="utf-8"?>
<CommandTable xmlns="...">
<Extern href="stdidcmd.h" mce_href="stdidcmd.h"/>
<Extern href="vsshlids.h" mce_href="vsshlids.h"/>
<Extern href="msobtnid.h" mce_href="msobtnid.h"/>
<Commands package="guidHowToPackagePkg">
<Menus>
<Menu guid="guidHowToPackageCmdSet" id="TopLevelMenu" priority="0x100"
type="Menu">
<Parent guid="guidSHLMainMenu" id="IDG_VS_MM_BUILDDEBUGRUN" />
<Strings>
<ButtonText>HowToPackage</ButtonText>
<CommandName>HowToPackage</CommandName>
</Strings>
</Menu>
</Menus>
<Groups>
<Group guid="guidHowToPackageCmdSet" id="TopLevelMenuGroup"
priority="0x0600">
<Parent guid="guidHowToPackageCmdSet" id="TopLevelMenu"/>
</Group>
<Group guid="guidHowToPackageCmdSet" id="TopLevelMenuGroup2"
priority="0x0600">
<Parent guid="guidHowToPackageCmdSet" id="TopLevelMenu"/>
</Group>
</Groups>
<Buttons>
<Button guid="guidHowToPackageCmdSet" id="cmdFirstCommand" priority="0x0100"
type="Button">
<Parent guid="guidHowToPackageCmdSet" id="TopLevelMenuGroup" />
<Strings>
<CommandName>cmdidFirstCommand</CommandName>
<ButtonText>First Command</ButtonText>
</Strings>
</Button>
<Button guid="guidHowToPackageCmdSet" id="cmdSecondCommand"
priority="0x0101" type="Button">
<Parent guid="guidHowToPackageCmdSet" id="TopLevelMenuGroup" />
<Strings>
<CommandName>cmdidSecondCommand</CommandName>
<ButtonText>Second Command</ButtonText>
</Strings>
</Button>
<Button guid="guidHowToPackageCmdSet" id="cmdThirdCommand" priority="0x0102"
type="Button">
<Parent guid="guidHowToPackageCmdSet" id="TopLevelMenuGroup2" />
<Strings>
<CommandName>cmdidThirdCommand</CommandName>
<ButtonText>Third Command</ButtonText>
</Strings>
</Button>
<Button guid="guidHowToPackageCmdSet" id="cmdFourthCommand"
priority="0x0102" type="Button">
<Parent guid="guidHowToPackageCmdSet" id="TopLevelMenuGroup2" />
<Strings>
<CommandName>cmdidFourthCommand</CommandName>
<ButtonText>Fourth Command</ButtonText>
</Strings>
</Button>
</Buttons>
</Commands>
<Symbols>
<!-- This is the package guid. -->
<GuidSymbol name="guidHowToPackagePkg"
value="{0380775d-5735-43ed-8c23-c1fda451e1c8}" />
<GuidSymbol name="guidHowToPackageCmdSet"
value="{8D7B9CB3-3591-47f9-B104-B7EB173E0F03}" >
<IDSymbol name="TopLevelMenu" value="0x0100" />
<IDSymbol name="TopLevelMenuGroup" value="0x0200" />
<IDSymbol name="TopLevelMenuGroup2" value="0x0201" />
<IDSymbol name="cmdFirstCommand" value="0x0300" />
<IDSymbol name="cmdSecondCommand" value="0x0301" />
<IDSymbol name="cmdThirdCommand" value="0x0302" />
<IDSymbol name="cmdFourthCommand" value="0x0303" />
</GuidSymbol>
<!-- Other Guids for the package -->
</Symbols>
</CommandTable>
To recall how this .vsct file results the menu shown above I tell you a few details. We declared a Menu element for the top menu. The commands are represented by four Button elements and are divided into two Group elements. Each button references the corresponding Group element as its parent; Groups use the Menu element as their parent.
We are going to turn this .vsct file to use a submenu for the third and fourth buttons. To achieve this we make the following steps:
Step 1: Rename the TopLevelMenuGroup2 to SubMenuGroup (and all references). We turn the group of third and fourth command into a submenu group.
Step 2: Add a new menu representing the submenu and attach it to the TopLevelMenuGroup.
Step 3: Attach the SubMenuGroup to the newly created submenu.
In the following code I indicate the changes (note, this is not the full code!):
<?xml version="1.0" encoding="utf-8"?>
<CommandTable xmlns="...">
<!-- Extern section unchanged -->
<Commands package="guidHowToPackagePkg">
<Menus>
<!-- New menu added -->
<Menu guid="guidHowToPackageCmdSet" id="SubMenu" priority="0x200"
type="Menu">
<Parent guid="guidHowToPackageCmdSet" id="TopLevelMenuGroup" />
<Strings>
<ButtonText>Other Commands</ButtonText>
<CommandName>Other Commands</CommandName>
</Strings>
</Menu>
</Menus>
<Groups>
<!-- Group changed to SubMenuGroup and attached to SubMenu -->
<Group guid="guidHowToPackageCmdSet" id="SubMenuGroup"
priority="0x0600">
<Parent guid="guidHowToPackageCmdSet" id="SubMenu"/>
</Group>
</Groups>
<Buttons>
<!-- We attached these two buttons to SubMenuGroup -->
<Button guid="guidHowToPackageCmdSet" id="cmdThirdCommand" priority="0x0102"
type="Button">
<Parent guid="guidHowToPackageCmdSet" id="SubMenuGroup" />
<Strings>
<CommandName>cmdidThirdCommand</CommandName>
<ButtonText>Third Command</ButtonText>
</Strings>
</Button>
<Button guid="guidHowToPackageCmdSet" id="cmdFourthCommand"
priority="0x0102" type="Button">
<Parent guid="guidHowToPackageCmdSet" id="SubMenuGroup" />
<Strings>
<CommandName>cmdidFourthCommand</CommandName>
<ButtonText>Fourth Command</ButtonText>
</Strings>
</Button>
</Buttons>
</Commands>
<Symbols>
<!-- We add a new ID -->
<GuidSymbol name="guidHowToPackageCmdSet"
value="{8D7B9CB3-3591-47f9-B104-B7EB173E0F03}" >
<IDSymbol name="SubMenu" value="0x0101" />
</GuidSymbol>
</Symbols>
</CommandTable>
Please note the priority attribute of the new menu: the value of 0x0200 ensures that the submenu will appear after the first and second command:

Creating a toolbar
In many cases a toolbar represents commands in a more useful way than a menu does. In this part we are going to turn the menu above into a toolbar and then playing with a few options.
Instead of telling all the details of how I retailored the .vsct file, here is the solution that is intended to make the menu-to-toolbar transformation:
<?xml version="1.0" encoding="utf-8"?>
<CommandTable xmlns="...">
<!-- Extern section unchanged -->
<Commands package="guidHowToPackagePkg">
<Menus>
<Menu guid="guidHowToPackageCmdSet" id="HowToToolbar" priority="0x0000"
type="Toolbar">
<Parent guid="guidHowToPackageCmdSet" id="HowToToolbar" /> <CommandFlag>DefaultDocked</CommandFlag>
<Strings>
<ButtonText>HowToPackage</ButtonText>
<CommandName>HowToPackage</CommandName>
</Strings>
</Menu>
</Menus>
<Groups>
<Group guid="guidHowToPackageCmdSet" id="HowToToolbarGroup"
priority="0x0600">
<Parent guid="guidHowToPackageCmdSet" id="HowToToolbar"/>
</Group>
</Groups>
<Buttons>
<Button guid="guidHowToPackageCmdSet" id="cmdFirstCommand" priority="0x0100"
type="Button">
<Parent guid="guidHowToPackageCmdSet" id="HowToToolbarGroup" />
<Strings>
<CommandName>cmdidFirstCommand</CommandName>
<ButtonText>First Command</ButtonText>
</Strings>
</Button>
<!-- Declaration of other buttons is straightforward, code omitted -->
</Commands>
<Symbols>
<GuidSymbol name="guidHowToPackageCmdSet"
value="{8D7B9CB3-3591-47f9-B104-B7EB173E0F03}" >
<IDSymbol name="HowToToolbar" value="0x0100" />
<IDSymbol name="HowToToolbarGroup" value="0x0200" />
<!-- No change for command IDs -->
</GuidSymbol>
</Symbols>
</CommandTable>
The key change is the new form of Menu element that uses the Toolbar value in its type attribute. In the example before standard menus had parent groups (defined by Visual Studio). However, for toolbars the concept of parent menu or menu group has no meaning just like as nesting toolbars has not. As a convention, we set the Parent of a toolbar to the same GUID and ID pair as we use for the toolbar identification.
The first time we show up the toolbar we want it to be docked so we set a CommandFlag with the value of DefaultDocked.
Now, we can build our project and see how the toolbar works. Let’s start debugging and make the toolbar visible by enabling our toolbar with View|Toolbars|HowtoPackage menu item. Our toolbar will be shown but we do not see the buttons, only just their placeholders:

Why is this so? We have button elements on the toolbar. When placing them, their default appearance is “icon only”. However in the .vsct file we did not declare icons for the buttons. We can define and set icons or change the default appearance option for buttons. I demonstrate you both. To show the button text in toolbars, add the following CommandFlag to each buttons:
<CommandFlag>TextOnly</CommandFlag>
The resulting toolbar now shows our buttons:
However, this is the concept that is a total misusage of toolbars. So, let’s move on using icons. To set up button icons we are going to use exactly the same code as we used in the samples in Part #14. We remove the TextOnly command flags from buttons and add icons to them with a corresponding image definition. For example, we add the following definition for the first button:
<Button guid="guidHowToPackageCmdSet" id="cmdFirstCommand" priority="0x0100"
type="Button">
<Parent guid="guidHowToPackageCmdSet" id="HowToToolbarGroup" />
<Icon guid="guidImages" id="bmpPic1" />
<!-- Other elements of the button definition -->
</Button>
We define the button images with the Bitmap and corresponding GuidSymbol sections:
<Commands>
<!-- Other elements -->
<Bitmaps>
<Bitmap guid="guidImages" href="Resources\Images_32bit.bmp" mce_href="Resources\Images_32bit.bmp"
usedList="bmpPic1, bmpPic2, bmpPicSearch, bmpPicX, bmpPicArrows"/>
</Bitmaps>
<!-- Other elements -->
</Commands>
<GuidSymbol name="guidImages" value="..." >
<IDSymbol name="bmpPic1" value="1" />
<IDSymbol name="bmpPic2" value="2" />
<IDSymbol name="bmpPicSearch" value="3" />
<IDSymbol name="bmpPicX" value="4" />
<IDSymbol name="bmpPicArrows" value="5" />
</GuidSymbol>
This result rather resembles to a toolbar than the one before using the TextOnly flags:
With toolbars we can use some other controls. Let’s see a few examples!
Menu controllers on toolbars
Till this time we have seen examples for two kinds of menus: standard menus and submenus. On toolbars we can use a third kind of menu called menu controller: this is split-button drop-down menu. We change the toolbar above so that the last three buttons go into a menu controller:
To move the buttons into the menu controller, we have to do the following steps:
Step 1: We create IDs for new elements.
Step 2: Create a Menu item representing the menu controller.
Step 3: Create a Group item for encapsulate the buttons that will appear in the menu controller.
Step 4: Attach the button items to the Group created in the third step.
The changes related to these steps result in the following code:
<?xml version="1.0" encoding="utf-8"?>
<CommandTable xmlns="...">
<!-- Extern section unchanged -->
<Commands package="guidHowToPackagePkg">
<Menus>
<!-- New item representing the menu controller -->
<Menu guid="guidHowToPackageCmdSet" id="HowToMenuController"
priority="0x0200" type="MenuController">
<Parent guid="guidHowToPackageCmdSet" id="HowToToolbarGroup"/>
<CommandFlag>IconAndText</CommandFlag>
<Strings>
<ButtonText>HowTo Controller</ButtonText>
<CommandName>HowTo Controller</CommandName>
</Strings>
</Menu>
</Menus>
<Groups>
<!-- New group for the items in the menu controller -->
<Group guid="guidHowToPackageCmdSet" id="HowToControllerGroup"
priority="0x0600">
<Parent guid="guidHowToPackageCmdSet" id="HowToMenuController"/>
</Group>
</Groups>
<Buttons>
<!-- We leave the first button as it is (cmdFirstCommand) -->
<!-- We change the 2nd 3rd and 4th button as indicated -->
<Button guid="guidHowToPackageCmdSet" id="cmdSecondCommand"
priority="0x0101" type="Button">
<Parent guid="guidHowToPackageCmdSet" id="HowToControllerGroup" /> <CommandFlag>IconAndText</CommandFlag>
<Icon guid="guidImages" id="bmpPic2" />
<Strings>
<CommandName>cmdidSecondCommand</CommandName>
<ButtonText>Second Command</ButtonText>
</Strings>
</Button>
<!-- Code for the 3rd and 4th button is similar -->
</Buttons>
<!-- Bitmaps section unchanged -->
</Commands>
<Symbols>
<GuidSymbol name="guidHowToPackageCmdSet" value="..." >
<!-- We use these two new IDs -->
<IDSymbol name="HowToMenuController" value="0x0101" />
<IDSymbol name="HowToControllerGroup" value="0x0201" />
</GuidSymbol>
<!-- Other Guids for the package -->
</Symbols>
</CommandTable>
The Menu item for a menu controller can be defined so that the type attribute is set to MenuController. The Parent of our menu is the command group representing the four command button as we used in the previous example.
We attach the newly created group to the Menu item above and then attach the last three button to this Group. We change the CommandFlag elements for the new menu controller item and for the tree involved button to IconAndText in order to make it dropdown-menu-like. That’s all to get the result I have indicated in picture above!
Just a short remark to the IconAndText command flags. This is the default value for the buttons attached to a menu controller, so if you leave them for buttons, the toolbar appearance will not change. However, for the menu controller itself the default mode displays only the icons. If we had omitted the IconAndText flag from the controller definition we could see the following toolbar:
A menu controller remembers the command we used last time. When the click on the third command, after the command executes the toolbar indicates that command as last used:

Combo boxes
The VSCT file format allows us defining combo boxes with different styles:
Drop-down combo. This type of combo box allows the user to select an item from the predefined ones and no other text values can be typed in.
Dynamic combo. The user can select an item from the list of combo box and also can type its own text.
Indexed combo. From the point of user it works on the same way as the dynamic combo. However the programming model is a bit different. While the dynamic combo raises a selection event with the text selected (or typed), indexed combo raises this event with the index of the selected item.
MRU combo. A combo box that remembers for the last 16 item typed in (per combo). The user can use it to type in text or select one from the previously typed ones.
The package owning the combo box is responsible for filling up its content. The IDE communicates with the package through events.
Using combos is a bit more difficult that buttons and menus. Here in this article I will not treat them, in a later article I will go into the syntax and programming model as well.
Using shortcut keys
Developers programming WinForms applications know that menu items can have shortcut keys to access them from the keyboard. Visual Studio users also know these shortcuts since they often use them. In this part I show you how to handle this with commands defined in a .vsct file.
While in WinForms programming we generally assign shortcut keys to menu items, in VSX shortcuts are assigned to commands. Since the same command can be used in different contexts, shortcuts of commands are also interpreted in different contexts. It might be so that in a certain context a command does not have a keyboard shortcut while in another it has. In a third context the command may even have a different shortcut.
The VSCT schema has an element called KeyBinding that is nested into the KeyBindings container like in the following example:
<?xml version="1.0" encoding="utf-8"?>
<CommandTable xmlns="..." xmlns:xs="...">
<Commands package="...">
<!-- Command information goes here
</Commands>
<KeyBindings>
<KeyBinding guid=".." id=".." ... />
<!-- More key bindings -->
</KeyBindings>
</CommandTable>
Please note, that KeyBindings is located outside of the Command element, directly within the CommandTable element. The keyboard shortcuts can be easily described like in the following sample:
<KeyBindings>
<KeyBinding guid="guidHowToPackageCmdSet" id="cmdShowLearnVSXNowTool"
editor="guidVSStd97"
key1="VK_F7" mod1="Control Alt"
key2="VK_F1">
</KeyBinding>
</KeyBindings>
You can assign not only a simple hotkey for a command but also two. The key1 and mod1 attributes set the first hotkey, key2 and mod2 the second one. These hotkeys are not alternatives of each other: you have to press the first then the second to activate the command.
For example, in the code above your first key is Ctrl+Alt+F7, the second F1. In values of key1 and key2 attributes you can use typable alphanumeric characters, VK_ constants (IntelliSense will offer you as you type) or two digit hexadecimal constants with 0x prefix.
The values of mod1 and mod2 specify the modification keys. You can use the Control, Alt and Shift values or a combination of them where the value elements are separated by a space.
With the guid and id attributes we can bind the specified key combination to the appropriate command. The editor attribute defines the context for a specific binding. The guidVSStd97 value defines that the command is global, so it is available in anywhere in Visual Studio.
Using visibility contexts
In Part #13 I have already treated the concept of visibility contexts. Visual Studio defines so-called contexts and always knows which one is current. Each context is identified with a GUID that can be accessed through the VSConstants helper type (see the table for field names). I summarize the predefined context types in the following table:
| Context name |
Description |
| UICONTEXT_NoSolution |
No solution is opened in the VS IDE (the Solution Explorer tool window is empty).
|
| UICONTEXT_SolutionExists |
There is an existing solution opened in VS IDE. This can be an empty solution, a solution created by opening a single file, a solution with one or more project, etc. Commands bound to this context are visible if you can see a root solution in the Solution Explorer.
|
| UICONTEXT_EmptySolution |
There is a solution opened in the VS IDE and this solution is empty (does not contain any item).
|
| UICONTEXT_SolutionHasSingleProject |
There is a solution opened in the VS IDE and this solution contains exactly one project of any type.
|
| UICONTEXT_SolutionHasMultipleProjects |
There is a solution opened in the VS IDE and this solution contains more than multiple projects loaded.
|
|