How VSPackages Add User Interface Elements
Visual Studio 2008 architecture enables a VSPackage to add UI elements such as menus, toolbars, and toolbar windows to the IDE.
Nota
Beginning with Visual Studio 2008 SDK, use XML Command Table (.vsct) files instead of command table configuration (.ctc) files to define how menus and commands appear in your VSPackages. For more information, see XML-Based Command Table Configuration (.vsct) Files.
Architectural Requirements
The set of rules and structures that enables interface customization on a per-VSPackage basis is called the Command Table Architecture. To better understand the Command Table Architecture, consider the following design issues that must be addressed when a Visual Studio 2008 VSPackage makes its command set available to the IDE.
Avoid User Interface Clutter and Confusion
There might be any number of VSPackages installed in the Visual Studio 2008 session that eventually hosts your VSPackage. When your VSPackage adds commands, it must not only avoid breaking previously installed VSPackages but should ideally make its features available to other VSPackages as well. It should also allow additions to its own feature set through the contributions of other VSPackages.
Every menu — whether accessed through the main menu bar, a submenu of the menu bar, or from a context menu — can contain all the menu items contributed by all other VSPackages. Because of this, you need to beware of overcrowding the UI. If there are too many commands displayed at once, the UI can become confusing and overwhelm users.
The User Interface is Dynamic, Not Static
Your commands can be displayed or hidden at any given time, depending on the state of the underlying data as well as the user's current activity.
A VSPackage must be allowed to change the label of a UI item as well as the contents of its combo boxes or menus.
Sometimes UI items may need to be added or removed during the VSPackage's use.
Some UI items may require additional calls to the VSPackage to populate their values or detect their current state. These items include most-recently-used (MRU) files lists, combo boxes, and selectors for color or texture.
Sometimes it is better to add your command to a menu regardless of the VSPackage in which the menu appears. For instance, if you write a VSPackage that provides commands similar to Cut, Copy, or Paste, your new commands should appear everywhere these other items appear regardless of the VSPackage.
The User Interface is Customizable
A user can at any time choose to customize any UI elements your VSPackage provides, such as adding a button to a tool window or rearranging a menu. In some cases you may want to prevent this from happening.
Some commands are available only through customization: that is, a command might not be accessible through a menu or toolbar until the user opens the Customize dialog box from the Tools menu and adds the command to a menu or toolbar.
The user can at any time customize the key bindings of the IDE, such as making one of your commands accessible through a keystroke. This is in addition to key bindings that Visual Studio 2008 applies based on your chosen IDE.
The user can execute your menu command from the Command window, so the IDE needs to know which command corresponds to a command's printed label, a process known as "canonicalization." For instance, the canonicalization of '&File Open' is 'FileOpen'.
The User Interface Should Be Helpful
Most UI items need tooltips.
For performance reasons, you should load your VSPackage only if one of its functions is invoked. This is known as "delayed loading."
All additions to the IDE requested by a VSPackage should be localizable.
You can use standard bitmaps or custom ones of your choosing.
The Command Table Architecture
The abstractions, data structures, and tools of the Command Table Architecture fulfill all of the requirements listed earlier.
Three broad tenets make up the foundation of the Command Table Architecture:
There are three basic kinds of items: MENU, GROUP, and COMMAND. MENU and GROUP serve as containers for both MENUs and COMMANDs. COMMANDs are actual procedures that the user can execute against the IDE.
Each item is specified by an item definition that describes the item, its priority relative to other items, and the flags that modify its behavior.
Each item has a placement that describes the parent of the item. An item can have multiple parents, in which case the items appear in multiple places in the UI.
For an example of how menus and commands are implemented in a VSPackage, see the C# Single View Editor Reference Sample. By default, this sample is located in: C:\Program Files\Visual Studio 2008 SDK\<version number>\VisualStudioIntegration\Samples\IDE\CSharp\Reference.SingleViewEditor. The …\CtcComponents folder contains three files: CommandID.h, Guids.h, and PkgCmd.ctc. CommandID.h contains definitions for menus and menu groups, Guids.h defines the command groups, and PkgCmd.ctc maps commands to the command and menu groups.
How Items Are Defined
No matter what item you are defining, the first field of the definition is always the item's unique identifier and has the format GUID:ID, where ID are the identifiers for one or more commands. An example GUID format is:
#define guidCmd { 0xBC8DA515, 0x5743, 0x4FEB, { 0xA9, 0x29, 0x29, 0x38, 0x24, 0x9C, 0xBA, 0x26 } }
The two parts that make up a single item's definition are:
#define guidCmd { 0xBC8DA515, 0x5743, 0x4FEB, { 0xA9, 0x29, 0x29, 0x38, 0x24, 0x9C, 0xBA, 0x26 } }
#define cmdid 1
// This is a valid value for the first parameter of the definition.
guidCmd:cmdid
Nota
Create your own unique GUID in the Visual Studio SDK by using the Create GUID tool on the Tools menu.
The second parameter indicates the item's parent; that is, the collection that the item belongs to. The item's parent does not have to be specified when the item is defined. You can make the value of the second parameter either the same as the value of the first parameter or you can specify GUID:0. For example:
// The item's id is a valid value for the parent parameter.
guidCmd:cmdid
// So is the command value of 0.
guidCmd:0
A potential source of confusion occurs when you define a group or menu ID that evaluates to 0. GUID:0 is always reserved to mean no parent or self-parent. So if a command is marked with a group that has an ID of 0, the command does not appear because the .ctc compiler sees only a parent of GUID:0. This means that you should always use a nonzero ID for any command, group, or menu.
MENU, GROUP, and COMMAND Items
The Command Table Architecture section describes how items are defined and their parents specified. As mentioned previously, these items come in three varieties: GROUP, MENU, and COMMAND.
GROUP
A group is an item defined in the NEWGROUPS_BEGIN – NEWGROUPS_END section of the .ctc file. For more information about .ctc files, see Command Table Configuration (.Ctc) Files. A group can call either a menu, another group, or GUID:0, its parent. A group can be placed on multiple menus by referencing each one as its parent in the CMDPLACEMENT_SECTION – CMDPLACEMENT_END section. This nomenclature might seem a bit confusing since the words CMDPLACEMENT_SECTION and CMDPLACEMENT_END suggest commands rather than groups. But adding a command to a group adds that command everywhere that the group appears. Even if a group is not defined in your VSPackage, you can still add your own commands to it. For more information, see Default Commands, Groups, and Toolbars.
Menu separators are automatically added around items that belong to the same group, except if the separator happens to be at the top or bottom of the menu. This is the only way to add menu separators. Correctly adding items to groups automatically adds separators.
The IDE provides a number of predefined default groups that VSPackages can add new commands or menus to.
Nota
A group's location beneath a given menu is determined by the group, not the menu. In other words, a group's definition gives no indication of its contents when devenv.exe /setup completes its execution.
MENU
A menu item is a single line item defined in the MENUS_BEGIN – MENUS_END section of the .ctc file. Consider a menu item as a container or placeholder that is not executable by the user and contains either commands or additional menu items or both. One or more groups can have the same menu item as a parent. The parent for a menu item is either itself or the group (which is GUID:0).
Nota
Since groups choose which menu to become a member of, menus have no control over which groups they host. In other words, a menu's definition gives no indication of what is in that menu when devenv.exe /setup completes its execution.
COMMAND
An individual command provided to the IDE is defined in either the BUTTONS_BEGIN – BUTTONS_END or COMBOS_BEGIN – COMBOS_END section of the .ctc file. The parent of items defined in BUTTONS_BEGIN – BUTTONS_END must be the command GUID:0, the items themselves, or a group. The parent cannot be a menu item. A command can be placed in multiple groups by referencing each group as a parent in the CMDPLACEMENT_SECTION – CMDPLACEMENT_END section. The visibility of an individual command is controlled by the visibility of the parent menu item of each group it belongs to. Of the types MENU, GROUP, and COMMAND, a command is what the user can actually select to interact with your VSPackage.
Your command must pass a series of tests for it to display and be enabled:
The command is placed correctly.
The command is not set to DEFAULTINVISIBLE.
The command is not invisible because of a context entry in VISIBILITY_SECTION – VISIBILITY_END.
VSPackage code that implements the IOleCommandTarget interface displays and enables your command; no interface code intercepted and acted on it.
When a user selects your command, it becomes subject to the procedure outlined in Command Routing Algorithm.
Nota
Commands add themselves to groups, so groups have no control over them.
The following terms describe some concepts unique to the Command Table Architecture.
Parent — the second parameter in the record that defines or places an item, where the first parameter is the item's unique id.
Siting — setting the second parameter as the parent when an item is defined or making subsequent entries in the CMDPLACEMENT_SECTION – CMDPLACEMENT_END section so that the command or menu will appear in additional locations.
Self Parenting or Self-Hosted — when the second parameter in an item's definition references the item itself or GUID:0 instead of the group or menu that the item is adding itself to. A self-parented item does not appear anywhere until it is placed.
Sub-Menu — a menu assigned to a parenting group for display under another menu.
Primary Parent Group — when an item is defined the first time and a parent is specified that is neither the item itself or GUID:0.
The following rules govern which items can call other items their parent.
Element |
Defined in this Section of the Command Table |
May be Contained by (as parent, by placement in CMDPLACEMENT_SECTION – CMDPLACEMENT_END, or both) |
May Contain (referred to as a parent) |
---|---|---|---|
Group |
NEWGROUPS_BEGIN – NEWGROUPS_END, the IDE, other VSPackages |
A menu, a group, the item itself, GUID:0 |
Menus, groups, and commands |
Menu |
MENUS_BEGIN – MENUS_END, the IDE, other VSPackages |
1 to n groups |
0 to n groups |
Toolbar |
MENUS_BEGIN – MENUS_END, the IDE, other VSPackages |
The item itself, GUID:0 |
- |
Command |
BUTTONS_BEGIN – BUTTONS_END, COMBOS_BEGIN – COMBOS_END,the IDE, other VSPackages |
1 to n groups, the item itself, GUID:0 |
- |
Menu, Command and Group Placement
For an item to appear in multiple locations, parents make additional entries in the CMDPLACEMENT_SECTION – CMDPLACEMENT_END section. The third field, Priority, is the item's placement with respect to other items. When the IDE merges two or more items with the same priority, the placement of each is undefined. This is because the IDE does not guarantee that package resources are always read in the same order each time devenv.exe /setup is executed.
First Entry |
Second Entry |
Priority |
Comment |
---|---|---|---|
Group |
Menu |
With respect to other groups that have this menu as a parent. |
The group adds itself to the menu. |
Group |
Group |
Items that belong to the group merge themselves based on their Priority. The precedence of priority is as initially defined, or as they are placed in a group. |
The group merges itself into the parent group. |
Menu |
Group |
With respect to other commands or menus in this group. |
The menu adds itself to a group. |
Command |
Group |
With respect to other commands or menus in this group. |
The command adds itself to the group wherever the group appears. |
The CMDPLACEMENT_SECTION – CMDPLACEMENT_END section does not apply to toolbars because toolbars cannot appear in multiple context-sensitive locations as menus do.
Command Visibility and Context
To avoid cluttered menus that might result from the installation of multiple VSPackages — where each VSPackage, loaded or not, can potentially add several menu items — the IDE allows users to specify the contexts in which menus and commands are visible. These conditional visibilities are described in the section VISIBILITY_SECTION – VISIBILITY_END. This section, however, does not apply to groups. If a menu or command is not referenced in this section, the default behavior is that it is always visible. A menu or command included in this section one or more times is visible only when one of the defined contexts is active.
Locally Overriding Commands
CMDUSED_SECTION - CMDUSED_END provides a way for VSPackages to locally override functions provided elsewhere.
Interface Element Appearance
Here are some considerations for selecting and placing command elements:
Visual Studio offers many different kinds of UI elements that have a different appearance based on their placement.
A UI element defined with the DEFAULTINVISIBLE flag will not display in the IDE until either your VSPackage's implementation of the QueryStatus(String, vsCommandStatusTextWanted, vsCommandStatus%, Object%) method displays it or the command is associated with a particular UI context in the VISIBILITY_SECTION – VISIBILITY_END section.
Even a successfully placed command may not display. This is because the IDE automatically hides or displays some commands based on interfaces that the VSPackage has (or has not) implemented. For example, a VSPackage's implementation of some build interfaces causes build-related menu items to be automatically shown.
Applying the COMMANDWELLONLY flag when a UI element is defined means that the command can be added only by customization.
Commands can be available only based on certain UI contexts, such as if a dialog box displays only while the IDE is in design view.
To display in the IDE, some UI elements require you to implement one or more interfaces or write some code.
This table describes UI elements and the flags that affect their appearance. See each section for additional flags that affect behavior.
Section Defined |
Appearance Flags |
Parent Group is a Menu |
Parent Group is a Toolbar |
---|---|---|---|
No flag, not even a placeholder: leave blank. |
Displays as a menu. |
The first menu label argument with a drop-down arrow to the right. If a second label argument was defined, that displays instead of the first. If there are no items, the menu does not display. |
|
TOOLBAR (Can be selected from the Toolbars submenu on the View menu.) |
Displays as a menu. |
Since a toolbar is a type of menu, a poor parenting choice can result in a toolbar with a menu parent. We advise that you do not do this as it results in a toolbar that tries to display under a menu item. |
|
TOOLWINDOWTOOLBAR (Does not display on the Toolbars submenu of the View menu.) |
- |
A toolbar inside a tool window. |
|
CONTEXT |
A popup menu, displayed by calling the ShowContextMenu method in the IVsUIShell interface. If a normal parent group is specified, acts like a normal menu or submenu. |
If a normal parent group is specified, acts like a normal drop-down menu on the toolbar. |
|
MENUCONTROLLER |
If the first menu controller item has an icon, the top level shows this icon and no text. If the first menu controller item has no icon, the top level shows only a drop-down arrow. The tooltip is always the first menu label argument. |
A split drop-down menu. |
|
MENUCONTROLLERLATCHED |
Same behavior as MENUCONTROLLER except that the item displayed in the controller is the item that is marked as latched or checked. |
Same behavior as MENUCONTROLLER. |
|
0 |
Is a menu item. |
Is an icon used as a button (if the command is defined with the Pict flag), or text used as a button (if the command is defined with the TextOnly flag). An icon is typically specified in the BITMAPS_BEGIN – BITMAPS_END section. |
|
DYNAMICITEMSTART (Requires additional code to fill the menu.) |
|||
SWATCH (Requires additional code to fill the menu.) |
|||
MRUCombo |
Populated by the VSPackage. |
||
DynamicCombo |
User can type into. |
||
DropDownCombo |
User cannot type into; command is text. |
||
IndexCombo |
Command identifier is the index. |
See Also
Concepts
Command Table Configuration (.Ctc) Files