Walkthrough: Creating a Tool Window (Part 2 of 4)

Tool windows are common in the Visual Studio integrated development environment (IDE). Some examples of tool windows that are included in Visual Studio are Solution Explorer, Task List, Error List, and the Output window. All tool windows have some features in common, for example, all can be docked in the IDE in the same manner. Predictable docking lets users manage their tasks and information efficiently.

This walkthrough teaches how to create a tool window in the Visual Studio IDE by using the following steps:

  • Create a tool window.

  • Embed a control in the tool window.

  • Add a toolbar to a tool window.

  • Add commands to the toolbar.

  • Implement the commands.

  • Set the default position for the tool window.

This walkthrough is part of a series that teaches how to extend the Visual Studio IDE. For more information, see Walkthroughs for Customizing Visual Studio By Using VSPackages.

Prerequisites

To complete this walkthrough, you must install the Visual Studio 2012 SDK.

Note

For more information about the Visual Studio SDK, see Extending Visual Studio Overview. To find out how to download the Visual Studio SDK, see Visual Studio Extensibility Developer Center on the MSDN Web site.

Locations for the Visual Studio Package Project Template

The Visual Studio Package project template is available in three locations in the New Project dialog box:

  • Under Visual Basic Extensibility. The default language of the project is Visual Basic.

  • Under C# Extensibility. The default language of the project is C#.

  • Under Other Project Types Extensibility. The default language of the project is C++.

Create a Tool Window

To create a tool window

  1. Create a VSPackage named FirstToolWin. You can also create a directory for the solution. Click OK.

  2. On the welcome page, click Next.

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

  4. Take a moment to examine the Basic VSPackage Information page. The value in the Company Name box is used as the namespace for all classes in the project. The VSPackage name box provides a name for the final compiled package and the VSPackage version box provides version information. Minimum Visual Studio edition specifies which Visual Studio editions the package should run on. The contents of the Detailed information box will appear on the properties page of the finished package. The Change Icon button lets you select an icon to represent the package.

    For this walkthrough, just accept the default values by clicking Next.

    Basic VSPackage Information

  5. On the Select VSPackage Options page, select Menu Command and Tool Window, and then click Next.

    VSPackage Options Dialogue

    Note

    The Menu Command option is required in the next walkthrough, Walkthrough: Extending the Tool Window (Part 3 of 4), which builds on this project.

  6. On the Menu Command Options page, in the Command name box, type Windows Media. In the Command ID box, type cmdidWindowsMedia, and then click Next.

    FirstTool_Win5A

  7. On the Tool Window Options page, in the Window name box, type Windows Media Player. In the Command ID field, type a valid identifier, for example, cmdidWindowsMediaWin, and then click Next.

    Tool Window Options Dialogue

  8. On the Select Test Project Options page, clear Integration Test Project and Unit Test Project, and then click Finish.

  9. In Solution Explorer, double-click MyControl.xaml.

  10. Right-click the Click Me! button, and then click Delete.

Embed a Control in the Tool Window

Next, add the Windows Media Player control to the Toolbox and then add it to the tool window.

To embed a control in the tool window

  1. In the Toolbox, expand the All WPF Controls section and look for Media Element.

  2. To add the Media Player to your tool window, drag the Media Element control from the Toolbox to the MyControl form.

  3. In the designer, select the Media Element control and then examine the available properties in the Properties window. Some of the properties are standard in all Windows Forms controls. However, others are supplied by the control, for example, Source, which is used to load a file at run time.

  4. On the File menu, click Save All.

Add a Toolbar to the Tool Window

By adding a toolbar in the following manner, you guarantee that its gradients and colors are consistent with the rest of the IDE.

To add a toolbar to the tool window

  1. In Solution Explorer, open FirstToolWin.vsct. The .vsct file defines the graphical user interface (GUI) elements in your tool window by using XML.

  2. In the <Symbols> section, find the <GuidSymbol> node whose name attribute is guidFirstToolWinCmdSet. Add the following two <IDSymbol> elements to the list of <IDSymbol> elements in this node to define a toolbar and a toolbar group.

    <IDSymbol name="ToolbarID" value="0x1000" />
    <IDSymbol name="ToolbarGroupID" value="0x1001" />
    
  3. Just above the <Groups> section, create a <Menus> section that resembles this:

    <Menus>
      <Menu guid="guidFirstToolWinCmdSet" id="ToolbarID"
            priority="0x0000" type="ToolWindowToolbar">
        <Parent guid="guidFirstToolWinCmdSet" id="ToolbarID" />
        <Strings>
          <ButtonText>Tool Window Toolbar</ButtonText>
          <CommandName>Tool Window Toolbar</CommandName>
        </Strings>
      </Menu>
    </Menus>
    

    All containers for commands are defined as different kinds of menus. By its type attribute, this one is set to appear as a toolbar in a tool window. The guid and id settings make up the fully qualified ID of the toolbar. Typically, the <Parent> of a menu refers to the containing group. However, a toolbar is defined as its own parent. Therefore, the same identifier is used for the <Menu> and <Parent> elements. The priority attribute is just '0'.

  4. Toolbars resemble menus in many ways. For example, just as a menu may have groups of commands, toolbars may also have groups. (On menus, the command groups are separated by horizontal lines. On toolbars, the groups are not separated by visual dividers.)

    Add a new <Group> element to the <Groups> section to define the group that you declared in the <Symbols> section.

    <Group guid="guidFirstToolWinCmdSet" id="ToolbarGroupID" priority="0x0000">
      <Parent guid="guidFirstToolWinCmdSet" id="ToolbarID"/>
    </Group>
    

    By setting the parent guid and id to the guid and id of the toolbar, you put the group in the toolbar.

  5. Save the file.

Add Commands to the Toolbar

Next, add commands to the toolbar. The commands will be displayed as buttons and controls.

To add commands to the toolbar

  1. In FirstToolWin.vsct, in the <Symbols> section, declare three commands just after the toolbar and toolbar group declarations.

    <IDSymbol name="cmdidWindowsMediaOpen" value="0x132" />
    <IDSymbol name="cmdidWindowsMediaFilename" value="0x133" />
    <IDSymbol name="cmdidWindowsMediaFilenameGetList" value="0x134" />
    

    Notice that the commands cmdidWindowsMedia and cmdidWindowsMediaWin are already declared.

  2. In the <Buttons> section, a <Button> element is already present and it contains a definition for the cmdidWindowsMedia and cmdidWindowsMediaWin commands. Add another <Button> element to define the cmdidWindowsMediaOpen command.

      <Button guid="guidFirstToolWinCmdSet"
            id="cmdidWindowsMediaOpen" priority="0x0101"
            type="Button">
      <Parent guid="guidFirstToolWinCmdSet"
              id="ToolbarGroupID"/>
      <Icon guid="guidImages" id="bmpPic1" />
      <Strings>
        <CommandName>cmdidWindowsMediaOpen</CommandName>
        <ButtonText>Load File</ButtonText>
      </Strings>
    </Button>
    

    Notice that the priority of the second button is 0x0101. The combo box that is added in the next step has the priority 0x0100. Therefore, the combo box will appear in the first position and the button will appear in the second position.

  3. To provide a place for the user to type some text, add a combo box. Adding a combo box is like adding a button, except that you define the combo box in a <Combos> section.

    Create a <Combos> section, just after the </Buttons> tag, that has one entry to define your combo box.

    <Combos>
      <Combo guid="guidFirstToolWinCmdSet"
             id="cmdidWindowsMediaFilename"
             priority="0x0100" type="DynamicCombo"
             idCommandList="cmdidWindowsMediaFilenameGetList"
             defaultWidth="130">
        <Parent guid="guidFirstToolWinCmdSet"
                id="ToolbarGroupID" />
        <CommandFlag>IconAndText</CommandFlag>
        <CommandFlag>CommandWellOnly</CommandFlag>
        <CommandFlag>StretchHorizontally</CommandFlag>
        <Strings>
          <CommandName>Filename</CommandName>
          <ButtonText>Enter a Filename</ButtonText>
        </Strings>
      </Combo>
    </Combos>
    
  4. Save and close FirstToolWin.vsct.

  5. In Solution Explorer, in the project folder, open PkgCmdID.cs or PkgCmdID.vb and then add the following lines in the class just after the existing members.

    Public Const cmdidWindowsMediaOpen As Integer = &H132
    Public Const cmdidWindowsMediaFilename As Integer = &H133
    Public Const cmdidWindowsMediaFilenameGetList As Integer = &H134
    Public Const ToolbarID As Integer = &H1000
    
    public const int cmdidWindowsMediaOpen = 0x132;
    public const int cmdidWindowsMediaFilename = 0x133;
    public const int cmdidWindowsMediaFilenameGetList = 0x134;
    public const int ToolbarID = 0x1000;
    

    Doing this makes your commands available in code.

  6. Save and close the file.

Implement the Commands

Now write the code that implements the commands.

To implement the commands

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

    Add the following code just after the existing using statements.

    Imports System.ComponentModel.Design
    
    using System.ComponentModel.Design;
    

    This line lets you use the CommandID class without having to fully qualify it.

  2. Add the following code to the constructor, just before the line that says control = new MyControl() (C#) or Me.Content = New MyControl() (VB).

    ' Create the toolbar.  
    Me.ToolBar = New CommandID(GuidList.guidFirstToolWinCmdSet, PkgCmdIDList.cmdidWindowsMediaWin)
    Me.ToolBarLocation = CInt(VSTWT_LOCATION.VSTWT_TOP)
    
    ' Create the handlers for the toolbar commands.  
    Dim mcs As OleMenuCommandService = TryCast(GetService(GetType(IMenuCommandService)), OleMenuCommandService)
    If mcs IsNot Nothing Then 
        Dim toolbarbtnCmdID As CommandID = New CommandID(GuidList.guidFirstToolWinCmdSet, PkgCmdIDList.cmdidMyCommand)
        Dim menuItem As MenuCommand = New MenuCommand(New EventHandler(AddressOf ButtonHandler), toolbarbtnCmdID)
        mcs.AddCommand(menuItem)
    
        ' Command for the combo itself  
        Dim menuMyDynamicComboCommandID As CommandID = New CommandID(GuidList.guidFirstToolWinCmdSet, CInt(PkgCmdIDList.cmdidMyCommand))
        Dim menuMyDynamicComboCommand As OleMenuCommand = New OleMenuCommand(New EventHandler(AddressOf ComboHandler), menuMyDynamicComboCommandID)
        mcs.AddCommand(menuMyDynamicComboCommand)
    
        ' Command for the combo's list  
        Dim comboListCmdID As CommandID = New CommandID(GuidList.guidFirstToolWinCmdSet, PkgCmdIDList.cmdidWindowsMediaWin)
        Dim comboMenuList As OleMenuCommand = New OleMenuCommand(New EventHandler(AddressOf ComboListHandler), comboListCmdID)
        mcs.AddCommand(comboMenuList)
    End If
    
    // 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. 
    var mcs = GetService(typeof(IMenuCommandService))
        as OleMenuCommandService;
    if (null != mcs)
    {
        var toolbarbtnCmdID = new CommandID(
            GuidList.guidFirstToolWinCmdSet,
            PkgCmdIDList.cmdidWindowsMediaOpen);
        var menuItem = new MenuCommand(new EventHandler(
            ButtonHandler), toolbarbtnCmdID);
        mcs.AddCommand(menuItem);
    
        // Command for the combo itself 
        var menuMyDynamicComboCommandID = new CommandID(
            GuidList.guidFirstToolWinCmdSet,
            (int)PkgCmdIDList.cmdidWindowsMediaFilename);
        var menuMyDynamicComboCommand = new OleMenuCommand(
            new EventHandler(ComboHandler),
            menuMyDynamicComboCommandID);
        mcs.AddCommand(menuMyDynamicComboCommand);
    
        // Command for the combo's list 
        var comboListCmdID = new CommandID(
            GuidList.guidFirstToolWinCmdSet,
            PkgCmdIDList.cmdidWindowsMediaFilenameGetList);
        var comboMenuList = new OleMenuCommand(
            new EventHandler(ComboListHandler), comboListCmdID);
        mcs.AddCommand(comboMenuList);
    } 
    

    This code adds three commands, one for the button and two for the combo box. The combo box requires two commands, one for when the user makes an entry, and one to fill the drop-down list.

  3. Assign the created user control to the local control variable. Change the last line in the constructor to read base.Content = control = new MyControl() or Me.Content = control = New MyControl().

  4. From the event handlers for the toolbar controls, your code must be able to access the Media Player control, which is a child of the MyControl class.

    In Solution Explorer, right-click MyControl.xaml, click View Code, and add the following code to the MyControl Class.

    Public ReadOnly Property MediaPlayer() As System.Windows.Controls.MediaElement
        Get 
            Return MediaElement1
        End Get 
    End Property
    
    public System.Windows.Controls.MediaElement MediaPlayer
    {
        get { return mediaElement1; }
    }
    
  5. Save the file.

  6. Return to MyToolWindow.cs or MyToolWindow.vb, and add the following code at the end of the class, just before the two final closing braces (C#) or the End Class statement (Visual Basic).

    Private Sub ButtonHandler(ByVal sender As Object, ByVal arguments As EventArgs)
        If comboValue IsNot Nothing AndAlso comboValue.Trim().Length <> 0 Then
            LoadFile(comboValue)
        End If 
    End Sub 
    
    Private Sub ComboHandler(ByVal sender As Object, ByVal arguments As EventArgs)
        Dim eventArgs As OleMenuCmdEventArgs = TryCast(arguments, OleMenuCmdEventArgs)
        If eventArgs IsNot Nothing Then 
            Dim output As IntPtr = eventArgs.OutValue
            Dim input As Object = eventArgs.InValue
            If input IsNot Nothing Then
                comboValue = input.ToString()
            ElseIf output <> IntPtr.Zero Then
                Marshal.GetNativeVariantForObject(comboValue, output)
            End If 
        End If 
    End Sub 
    
    Public Sub LoadFile(ByVal comboValue As String)
        control.MediaPlayer.Source = New Uri(comboValue)
    End Sub 
    
    Private Sub ComboListHandler(ByVal sender As Object, ByVal arguments As EventArgs)
    End Sub
    
    private void ButtonHandler(object sender,
    EventArgs arguments)
        {
            if (comboValue != null && comboValue.Trim().Length != 0)
            {
                LoadFile(comboValue);
            }
        }
    
        private void ComboHandler(object sender, EventArgs arguments)
        {
            var 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.Source = new System.Uri(comboValue);
        }
    
        private void ComboListHandler(object sender,
            EventArgs arguments)
        {
        }
    

    Notice that menuMyDynamicComboCommand and menuItem share the same event handler. Therefore, the tool window can play the file that is specified in the combo box. In this walkthrough, you do not provide code for the ComboListHandler function. In the next walkthrough, Walkthrough: Extending the Tool Window (Part 3 of 4), you add code that fills the drop-down list by using playlist names.

  7. The combo handler saves whatever is typed into it in a member variable. To add that variable, add the following code at the top of the class (in Visual Basic, after the Inherits statement). At the same time, add a member variable to hold the control.

    Dim control As MyControl
    Dim comboValue As String
    
    private MyControl control;
    string comboValue = "";
    

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

Set the Default Position for the Tool Window

Next, specify a default location in the IDE for the tool window. Configuration information for the tool window is in the FirstToolWinPackage.cs file.

To set the default position for the tool window

  1. In Solution Explorer, open FirstToolWinPackage.cs or FirstToolWinPackage.vb. In this file, find the ProvideToolWindowAttribute attribute on the FirstToolWinPackage class. This code is passing the MyToolWindow type to the constructor. To specify a default position, you must add more parameters to the constructor following example.

    <PackageRegistration(UseManagedResourcesOnly:=True), _
    InstalledProductRegistration("#110", "#112", "1.0", IconResourceID:=400), _
    ProvideMenuResource("Menus.ctmenu", 1), _
    ProvideToolWindow(GetType(MyToolWindow), Style:=Microsoft.VisualStudio.Shell.VsDockStyle.Tabbed, Window:="3ae79031-e1bc-11d0-8f78-00a0c9110057"), _
    Guid(GuidList.guidFirstToolWinPkgString)> _
    Public NotInheritable Class FirstToolWinPackage
        Inherits Package
    
    [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, which means that the window will be a tab in an existing window. The window is given by the Window named parameter; its value is a GUID. In this case, the GUID is the one for Solution Explorer.

    Note

    For more information about the GUIDs for windows in the IDE, see vsWindowKind Constants on the MSDN Web site.

  2. Save your work.

Testing the Tool Window

To test the tool window

  1. Press F5 to open a new instance of the Visual Studio experimental build.

  2. On the View menu, point to Other Windows and then click Windows Media Player.

    The media player tool window should open in the same window as Solution Explorer.

  3. In the combo box in the media player tool window, type the full path and file name of a supported sound or video file, for example, C:\windows\media\chimes.wav, press Enter, and then click the adjoining button.

    Note

    You have to enter a file name in the text box because the media player tool window does not have a File Open dialog box.

What's Next

In Walkthrough: Extending the Tool Window (Part 3 of 4), you can learn how to add more controls to the tool window. You add a button that displays a File Open dialog box, which you can use to select a file to play in the Media Player. You also add a drop-down list of playlists so that you can select one of them to play.

See Also

Tasks

Walkthrough: Adding a Toolbar to the IDE

Walkthrough: Adding a Toolbar to a Tool Window

Other Resources

Commands, Menus, and Toolbars