Walkthru:Adding a Toolbar 

Extensibility Guided Tour Send comments on this topic.
Walkthru:Adding a Toolbar

Glossary Item Box

Adding Toolbar Menus

Toolbars provide developers with the ability to quickly and easily access common tasks associated with their development efforts within the Visual Studio IDE. Within Visual Studio there are two general types of Toolbars that may be deployed. Toolbars bound to the IDE are the most common, but Visual Studio also allows Toolbars to be bound to custom Tool Windows. A good example would be the Toolbar bound to the Solution Explorer in Visual Studio. This Toolbar provides developers with quick access to common, Solution related, tasks. More importantly, the contents of the Toolbar alter to reflect the type of project currently selected by the Solution Explorer – a good example would be the buttons available only when doing web projects.

Adding Toolbars

Adding Toolbars to a VsPackage is a two-step process. First you add the relevant commands to a Command Table Configuration (.ctc) file, then compile them into a binary Command Table Output (.cto) file using the Binary Command Table Compiler. This process is the same whether creating extensibility via managed or native code and serves to create definitions for your commands as well as instructions on how to present them in the Visual Studio IDE. In this walkthrough you will add a simple Toolbar to the IDE to get the feel of how to work with CTC files and commands. To begin adding the Toolbar:

1.  In Solution Explorer, expand the CtcComponents folder in the DevAnnotater Project.

2.  Double-click on PkgCmdID.h to open it in a text editor. In the Menu IDs section, add a definition for the IDE Toolbar:

#define MyIDEToolbar 0x1010

3.  Then add an ID for a new Menu Group by adding the following definition to the Menu Group IDs section:

#define MyIDEToolbarGroup 0x1060

4.  Next, create a new command by placing the following code in the Command IDs section:

#define cmdidIDEToolbar 0x102

At this point you have created the definitions for a Toolbar (a specialized Menu), its associated Menu Group, along with a custom command that will be bound to a Button in the Toolbar. In the following steps you will specify graphical directives that will bind the objects you have just defined to the Visual Studio IDE.

5.  In Solution Explorer, double-click on DevAnnotater.ctc to open it for editing.

6.  Add a new Toolbar definition by adding the following code to the MENUS_BEGIN section of the CTC file:

guidDevAnnotaterCmdSet:MyIDEToolbar, // Menu/toolbar id/definition 
    guidDevAnnotaterCmdSet:MyIDEToolbar, // Menu Parent (self) 
    0x0000, // Priority (not used by toolbars) 
    TOOLBAR | DEFAULTDOCKED, // Attributes/Flags 
    "DevAnnotater"; // Toolbar display name 

The first line of the above code creates a new Menu ID which will be used to identify the menu and its constituent elements in remainder of the CTC file. CTC identifiers take the form of GUID:ID, where the GUID is the Guid representing one of the VsPackage's CommandSets (there can be more than one, though generally one is sufficient), and the ID is a unique ID, or handle, used to identify the resource in question. The second line above defines the parent of this object – but since Toolbars aren't nested in the Visual Studio IDE, Toolbars merely specify themselves as a parent object. Subsequent lines specify the priority and name of the toolbar – as well as provide attributes to the Visual Studio IDE informing it of the menu's behavior (i.e. specifying that the ‘menu' is actually a TOOLBAR, and should start docked to the other toolbars (as opposed to floating – like the macros toolbar)).

7.  Once the Toolbar's menu definition is in place, create a definition for the group of command items that will make up the actual commands on the toolbar itself by pasting the following code into the NEWGROUPS_BEGIN section of the CTC file:

guidDevAnnotaterCmdSet:MyIDEToolbarGroup, // Group ID 
    guidDevAnnotaterCmdSet:MyIDEToolbar, // Menu ID (i.e. parent) 
    0x0000; // Priority 

8.  Finally, bind the custom command to a button on the Toolbar by adding a new button definition (specifying the newly created group as the parent) to the BUTTONS_BEGIN section of the CTC file:

guidDevAnnotaterCmdSet:cmdidIDEToolbar, // command definition 
    guidDevAnnotaterCmdSet:MyIDEToolbarGroup, // parent 
    0x0100, // priority (relative to other commands on toolbar) 
    guidDevAnnotaterCmdSet:bmpPic2, // image/icon to use 
    BUTTON, 
    , 
    "Display Annotations Tool Window"; // tool tip text 

9.  Save your changes to DevAnnotater.ctc and close the file.

If you were to compile and deploy your project to Experimental Build now, you'd be able to load a new DevAnnotations Toolbar, and see that it had a single button. Pressing the button, however, would do nothing – as nothing currently exists to handle invocation of the command. In other words, CTC definitions and directives provide information to the Visual Studio IDE needed to display and ‘proffer' commands to end users. Moreover, each time one of these commands is invoked, the id of the invoked command, which you specified (i.e. 0x102), will be used to identify the invoked command and route it to the correct VsPackage as needed. All that remains, therefore, is to simply inform your VsPackage that you would like to handle invocation of your custom command. To do this, you merely need to add a few lines of code to the Initialize() method of your VsPackage, and then provide whatever custom logic you desire to handle the event raised by the IDE.

10.  Open PkgCmdID.cs by double clicking on it, and add the following constant definition to the static PkgCmdIDList class:

  public const int cmdidIDEToolbar= 0x102; 

This integer ID matches the same ID created in the PkgCmdID.h file – and serves to map unique command IDs between the COM oriented CTC files and your managed code. In other words, providing a reference to this ID in managed code will allow you to ‘watch' for events raised with this custom command ID. You could, obviously, just hard-code your scanning code with the 0x102 value, but placing it here serves to provide better factors and manageability of code.

11.  Save your changes to PkgCmdID.cs and close the file.

12.  Open VsPkg.cs and add the following using directives to the top of VsPkg.cs:

  using System.Windows.Forms; 
using Microsoft.VisualStudio; 

13.  Locate the Initialize() method (you may have to expand the Package Members code region). Here all of the command IDs exposed by the IDE have been mapped to matching event handlers within the VsPackage. Paste the following code below the code following the comment: "Create the command for the tool window" (i.e. near the bottom of the method, but still within the if block):

  // toolbar command:
CommandID toolbar = new CommandID(GuidList.guidDevAnnotaterCmdSet,
    (int)PkgCmdIDList.cmdidIDEToolbar);
MenuCommand tbButton = new MenuCommand(new EventHandler (ToolbarCallback), 
    toolbar);
mcs.AddCommand(tbButton);

Note that all this code does is create a new CommandID built from the Guid of the VsPackage's CommandSet, and from the integer value representing the command id to be targeted. Once that has been done, the code merely maps an event handler to respond to events bubbled up by the Visual Studio IDE each time the custom command is invoked.

14.  Now add the logic to handle invocation of the custom command by pasting the following method into VsPkg.cs (near the bottom of the class):

  private void ToolbarCallback(object sender, EventArgs e)
{
    ToolWindowPane win = this.FindToolWindow(
        typeof(MyToolWindow), 0, true);

    if (win == null || win.Frame == null)
        throw new COMException("Tool Window Not Present.");

    IVsWindowFrame frame = (IVsWindowFrame)win.Frame;
    int isVisible = frame.IsVisible();
    bool visible = isVisible == 0 ? true : false;

    string message;
    DialogResult res;
    if (visible)
    {
        message = "Annotation Tool Window is Already Active, " +
            "would you like to close it?";
        res = MessageBox.Show(message, "Close Tool Window?", 
            MessageBoxButtons.YesNoCancel);

        if (res == DialogResult.Yes)
            ErrorHandler.ThrowOnFailure(frame.Hide()); 
    }
    else
    {
        message = "Do you want to display the Annotations Tool Window?";

        res = MessageBox.Show(message, "Open Tool Window?", 
            MessageBoxButtons.YesNoCancel);

        if(res == DialogResult.Yes)
           ErrorHandler.ThrowOnFailure(frame.Show()); 
    }
}

As you can see, this code merely checks to see if the Annotations Window is already displayed. If it is not, it asks the end user if they would like to display it, and then does so based upon their choice – nothing complex, just an example of how you can respond with managed code to events raised by the Visual Studio IDE.

15.  Compile and deploy your changes to Experimental Build by pressing F5.

16.  Once Experimental Build loads, right click in the empty toolbar space just to the right of the Help menu in Experimental Build, and note the available toolbars.

A new toolbar for DevAnnotater has been added.

Note: If the Toolbar does NOT appear, then you will need to reset Experimental Build by using the VsRegEx command line tool (see step # 18 of the* Hello World sample for instructions). Once you have reset Experimental Build, redeploy by pressing F5 and the DevAnnotater *Toolbar will be in place.

17.  Enable the DevAnnotater Toolbar by clicking on it. Once you have enabled the DevAnnotater Toolbar, locate it in Experimental Build. (It will likely be placed either at the furthest right end of an existing ‘line' of toolbars, or down on its own new line – you can spot it because the icon is just a big "2" in a box.) This toolbar is no different than other Visual Studio Toolbars – meaning that you can drag it around and place it where desired and add or remove other buttons from it, etc.

18.  Click the single button available in the DevAnnotater Toolbar and a new MessageBox will appear asking whether you want to open or close the Annotations Tool Window (depending upon whether it is currently visible or hidden/inactive).

19.  Test out the Toolbar functionality a bit and then close Experimental Build before continuing to the next Walkthrough.