Tutorial 3: Creating Your First Tool Window

 

Tool windows are very common within the Visual Studio IDE. All tool windows have the same docking behavior within the environment to enable users to manage the large number of tasks and information they need to deal with inside the IDE. Some tool windows that you are most likely already familiar with are the Solution Explorer, Task List, Error List, and the Output window.

This tutorial focuses on creating a new tool window that lives inside the Visual Studio IDE.

You will how learn to:

  • Create a tool window.
  • Embed a control in the tool window.
  • Add a command bar into a tool window.
  • Set the default position for the tool window.

Steps

Create a tool window

  1. On the File menu, point to New, and then click Project. In the left pane, expand Other Project Types and click Extensibility. In the right pane, click Visual Studio Integration Package. Give your project a suitable name such as FirstToolWin. You can optionally create a directory for the solution. Click OK.

  2. On the wizard welcome page, click Next.

  3. Under Select a Programming Language, click Visual C#. Click Generate a new key file to sign the assembly, and then click Next.

  4. Under Basic VSPackage Information, type FirstToolWin in the VSPackage name field. Next to Minimum Visual Studio edition, click Standard. In the other fields, type whatever you want, and then click Next.

  5. On the Select VSPackage Options screen, check Tool Window, and then click Next.

  6. Under Tool Window Options, type Windows Media Player in the Window name field. In the Command ID field, type a valid identifier, such as cmdidWindowsMediaWin, and then click Finish.

  7. In Solution Explorer, double-click MyControl.cs.

    MyControl.cs opens in the designer.

  8. Click the existing button, and then press DEL to delete it so that the control looks like this:

Embed a control in the tool window

Next, you need to add the Windows Media Player control to the Toolbox.

  1. Under Toolbox, right-click the section where you'd like to add the control (the General section is a good one), and then click Choose Items.

  2. In the Choose Toolbox Items dialog box, click COM Components. Scroll down to and select the Windows Media Player check box, and then click OK.

    You now have a Windows Media Control tool in the Toolbox.

  3. Now you can add the Media Player to your form. Drag the Media Player control from the Toolbox onto the MyControls.cs form. Initially, it won't be very big, as shown here:

  1. With the Media Player control selected, go over to the Properties window and look at some of the properties that are available. Some of these are standard properties inherent in all Windows Forms controls; others are those supplied by the control, such as URL, which you use to load a file at runtime.
  2. With the Media Player control selected, set the Dock property to Fill.
  3. Save your work by clicking Save All on the File menu.

Add a command bar into the tool window

Adding a toolbar to a tool window is slightly different from adding a toolbar in a Windows Forms application. By adding a toolbar in the following way, you are ensuring that its gradients and colors are consistent with the rest of the IDE.

  1. In Solution Explorer, in the CtcComponents folder, open CommandIds.h.

  2. In the blank space after the lines with the comment Menu IDs, add the following code:

    #define ToolbarID 0x1000
    

    This line defines a new ID for the toolbar. You also need to define a group for the toolbar.

    #define ToolbarGroupID 0x1001
    
  3. Save the file and close it.

    The .CTC file defines the GUI elements present in your tool window.

  4. In the Solution Explorer, under the CtcComponents folder, open FirstToolWin.ctc.

    A toolbar is declared much the same way as a menu. Thus we'll add the information for the toolbar to the section of the file under the statement MENUS_BEGIN section.

  5. Add the following line under the MENUS_BEGIN declaration, under the existing comments, but before the MENUS_END line:

    guidFirstToolWinCmdSet:ToolbarID, guidFirstToolWinCmdSet:ToolbarID, 0x0000, TOOLWINDOWTOOLBAR, "My Toolbar";
    

    The first field in this comma-delimited string is the fully qualified ID of the toolbar, which you just added to the CommandsIds.h file. Normally the second field of a menu contains the parent of the menu. With a toolbar, however, you define the toolbar as its own parent. Thus, we used the same identifier for both of the first two fields. The third field is the priority, which is simply 0. The fourth field is the type of item we're defining; for toolbars we use TOOLWINDOWTOOLBAR. The final field is a string representing the name of this toolbar.

    The toolbar is in many ways analogous to a menu: just as a menu often has groups of menu items separated by horizontal lines, toolbars can also have groups. Thus we will define a group for this toolbar.

  6. Find the section in the file with the declaration NEWGROUPS_BEGIN. There is already a line for a menu group; add the following line after the existing line:

    guidFirstToolWinCmdSet:MyToolbarGroup, guidFirstToolWinCmdSet:MyToolbar, 0x0000;
    

    The first field in this comma-delimited string is the fully qualified ID of the group; this is the group ID that you added earlier to the CommandIds.h file. The second field is the toolbar ID. The third field is a priority; we're just leaving this 0.

Next, we'll add commands to the toolbar. The commands will exist as buttons and controls.

  1. Open CommandIds.h again (found in the CtcComponents folder).

  2. Add the following line shown in bold to the section under the comment Command IDs:

    ///////////////////////////////////////////////////////////////////////////////
    // Command IDs
    
    #define cmdidWindowsMedia 0x100
    #define cmdidWindowsMediaWin 0x101
    #define cmdidWindowsMediaOpen 0x102
    
  3. Save the file.

  4. Return to the FirstToolWin.ctc file. Add the following lines shown in bold to the BUTTONS_BEGIN section.

    BUTTONS_BEGIN
    // ...
    
    // Command                    Parent Group                Priority    Image            Type    Visibility        
    guidFirstToolWinCmdSet:cmdidWindowsMedia,    guidFirstToolWinCmdSet:MyMenuGroup,    0x0100, guidFirstToolWinCmdSet:bmpPic1, BUTTON, , "WindowsMedia";
    guidFirstToolWinCmdSet:cmdidWindowsMediaWin,    guidSHLMainMenu:IDG_VS_WNDO_OTRWNDWS1,    0x0100, guidFirstToolWinCmdSet:bmpPic2, BUTTON, , "Windows Media Player";
    guidFirstToolWinCmdSet:cmdidWindowsMediaOpen, guidFirstToolWinCmdSet:ToolbarGroupID, 2, guidFirstToolWinCmdSet:bmpPic1, BUTTON, "Load File";
    
    BUTTONS_END
    

    This code defines the command and specifies, through the second field, that it will appear in the toolbar group we defined earlier. Note that the third field priority is a 2 because we're also going to be adding a combo box to the toolbar; this button will be in the second position, with the combo box in first position (which will get priority 1).

  5. Save the file.

Adding a button is simple, but we'll need a place for the user to type in some text. We'll use the combo box for that. We follow a procedure similar to that for the button, by defining an ID for the combo box and by adding an entry to the .ctc file.

  1. In the Solution Explorer, inside the CtcComponents folder, open CommandIds.h.

  2. Add the following line shown in bold to the section under the comment Command IDs:

    ///////////////////////////////////////////////////////////////////////////////
    // Command IDs
    
    #define cmdidWindowsMedia 0x100
    #define cmdidWindowsMediaWin 0x101
    #define cmdidWindowsMediaOpen 0x102
    #define cmdidWindowsMediaFilename 0x103#define cmdidWindowsMediaFilenameGetList 0x104
    
  3. Save the file.

    This defined two commands, one for the combo box itself, and one that will be used to populate the combo box.

  4. Open FirstToolWin.ctc, also in the CtcComponents folder. We need to add a new section to the .ctc file for defining combo boxes.

  5. Find the BUTTONS_END line, and add the following code shown in bold after this line.

    BUTTONS_END
    
    COMBOS_BEGINCOMBOS_END
    

    These will define the starting and ending points of the combo box declarations.

  6. Now let's add the following code shown in bold in between the COMBOS_BEGIN and COMBOS_END lines.

    COMBOS_BEGIN
    
    guidFirstToolWinCmdSet:cmdidWindowsMediaFilename, guidFirstToolWinCmdSet:ToolbarGroupID, 1,cmdidWindowsMediaFilenameGetList, 130, DynamicCombo, IconAndText|CommandWellOnly,   "Filename:", "Filename:", "Enter Filename";
    
    COMBOS_END
    
  7. Save the file.

The toolbar is now defined. However, we need to add it to the tool window. The IDs you just created are in an .h file accessible to the .ctc file, but not accessible to the C# files. We also need to add the IDs to a C# file in the project.

  1. In the Solution Explorer, open PkgCmdID.cs, found in the root project folder.

  2. Add the following lines shown in bold inside the class immediately after the existing members:

    static class PkgCmdIDList
    {
        public const uint cmdidWindowsMedia = 0x100;
        public const uint cmdidWindowsMediaWin = 0x101;
        public const int cmdidWindowsMediaOpen = 0x102; // button    public const int cmdidWindowsMediaFilename = 0x103; // ComboBox    public const int cmdidWindowsMediaFilenameGetList = 0x104; // ComboBox list    public const int ToolbarID = 0x1000; // toolbar
    
    };
    
  3. Save the file.

    Now we'll write the code that adds the toolbar to the tool window.

  4. In the Solution Explorer, open MyToolWindow.cs, which contains the class for the tool window itself.

  5. Add the following line immediately after the existing using statements:

    using System.ComponentModel.Design;
    

    This line will allow us to use the CommandID class without needing to fully qualify it.

  6. Next, add the following bold code to the constructor:

    public MyToolWindow() :
        base(null)
    {
        // ...
        this.BitmapResourceID = 301;
        this.BitmapIndex = 1;
    
        // Create the toolbar
        this.ToolBar = new CommandID(GuidList.guidFirstToolWinCmdSet,        PkgCmdIDList.ToolbarID);    this.ToolBarLocation = (int)VSTWT_LOCATION.VSTWT_TOP;    // Create the handlers for the toolbar commands    OleMenuCommandService mcs = GetService(typeof        (IMenuCommandService)) as OleMenuCommandService;    if (null != mcs)    {        CommandID toolbarbtnCmdID = new CommandID(GuidList.guidFirstToolWinCmdSet,            PkgCmdIDList.cmdidWindowsMediaOpen);        MenuCommand menuItem = new MenuCommand(new EventHandler(ButtonHandler),            toolbarbtnCmdID);        mcs.AddCommand(menuItem);        // Command for the combo itself        CommandID menuMyDynamicComboCommandID = new CommandID(            GuidList.guidFirstToolWinCmdSet, (int)PkgCmdIDList.cmdidWindowsMediaFilename);        OleMenuCommand menuMyDynamicComboCommand = new OleMenuCommand(            new EventHandler(ComboHandler), menuMyDynamicComboCommandID);        mcs.AddCommand(menuMyDynamicComboCommand);        // Command for the combo's list        CommandID comboListCmdID = new CommandID(GuidList.guidFirstToolWinCmdSet,            PkgCmdIDList.cmdidWindowsMediaFilenameGetList);        OleMenuCommand comboMenuList = new OleMenuCommand(new EventHandler(ComboListHandler),            comboListCmdID);        mcs.AddCommand(comboMenuList);    }
        control = new MyControl();
    }
    

    This code adds three commands, one for the button, and two for the combo box. The combo box needs two commands, one for when the user makes an entry, and one to fill the dropdown list. Next we'll work on the event handlers used in this code.

    From the event handlers for the toolbar controls, we need to be able to access the Media Player control, which is a child of the MyControl class.

  7. Open MyControl.cs, and add the following code to the end of the file, before the final two closing braces:

    public AxWMPLib.AxWindowsMediaPlayer MediaPlayer
    {
        get { return axWindowsMediaPlayer1; }
    }
    
  8. Save MyControl.cs.

  9. Return to MyToolWindow.cs, and add the following code at the end of the class, just before the two final closing braces in the file:

    private void ButtonHandler(object sender, EventArgs arguments)
    {
        if (comboValue != null && comboValue.Trim().Length != 0)
        {
            LoadFile(comboValue);
        }
    }
    
    
    
    private void ComboHandler(object sender, EventArgs arguments)
    {
    
        OleMenuCmdEventArgs eventArgs = arguments as OleMenuCmdEventArgs;
        if (eventArgs != null)
        {
            IntPtr output = eventArgs.OutValue;
            object input = eventArgs.InValue;
            if (input != null)
            {
                comboValue = input.ToString();
            }
            else if (output != IntPtr.Zero)
            {
                Marshal.GetNativeVariantForObject(comboValue, output);
            }
        }
    
    }
    
    public void LoadFile(string comboValue)
    {
        control.MediaPlayer.URL = comboValue;
    }
    
    private void ComboListHandler(object sender, EventArgs arguments)
    {
    }
    

    Note that menuMyDynamicComboCommand and menuItem share the same event handler so we can conveniently get our tool window to play the file specified in the ComboBox. For now, we won't provide any code for the ComboListHandler function. In the next tutorial, we'll add code that fills the drop-down list with the playlist names.

  10. The combo handler saves whatever was typed into it in a member variable. To add that variable, add the following bold line at the top of the class:

    public class MyToolWindow : ToolWindowPane
    {
        string comboValue = ""; 
    

When the button is clicked, the button reads the value of this local variable and loads it into the Media Player.

Set the default position for the tool window

Next, we'll specify a default starting location for the tool window when the window is opened within the IDE. The information for configuring the tool window is in the VsPkg.cs file.

  1. In the Solution Explorer, find and open VsPkg.cs. Inside this file, you'll see the following line (about 45 lines down):

    [ProvideToolWindow(typeof(MyToolWindow))]
    

    ProvideToolWindow is an attribute class. This code is passing the MyToolWindow type to the constructor. To specify a default position, you need to add more parameters to the constructor.

  2. Replace the line with this:

    [ProvideToolWindow(typeof(MyToolWindow), Style = Microsoft.VisualStudio.Shell.VsDockStyle.Tabbed, Window = "3ae79031-e1bc-11d0-8f78-00a0c9110057")]
    

    The first named parameter is Style, and its value is Tabbed, meaning the window will be a tab in an existing window. The window is given by the Window named parameter; it's value is a GUID. In this case, the GUID is that for the Solution Explorer.

    Tip   The following page lists the GUIDs for the various windows:
    https://msdn2.microsoft.com/en-us/library/aa301252(VS.71).aspx

  3. Save your work.

Trying It Out

After completing these steps, you can try out the tool window. Click Debug/Start without debugging (or press CTRL+F5). A new instance of the experimental build of Visual Studio will open. You can now find your tool window by clicking View/Other Windows/Windows Media Player. It will initially open in the same window as the Solution Explorer.

You can try out the Media Player by typing in a full path and file name of an .avi file or an .mp3 file (for example, c:\windows\media\chimes.wav) into the Media Player toolbar, and then clicking the button next to the toolbar.

At this point there's no File Open dialog box, so you have to carefully type the file name or paste it in. In the next tutorial, we'll add a File Open dialog box.

What's Next

In the next lesson, we will take our Media Player tool window and add more controls to it, including a button that will display an Open File dialog box, which allows you to choose a file to play in the Media Player, as well as a drop-down list of playlists, which makes it possible for you to select one of your playlists to play. This will demonstrate how to populate a drop-down list on a toolbar, and how the controls can interact with one another.