Walkthrough: Extending the Tool Window (Part 3 of 4)

In this walkthrough, you add to the tool window that you created in Walkthrough: Creating a Tool Window (Part 2 of 4). You add a button that displays an Open File dialog box so that you can select a file to play in the Media Player.

This walkthrough shows how to add dynamic visibility to a menu command.

This walkthrough is one of a series that explains how to extend the Visual Studio integrated development environment (IDE). For more information, see Walkthroughs for Customizing Visual Studio By Using VSPackages.

Add Dynamic Visibility to a Menu Command

By default, menu commands are fixed in place and cannot be hidden after they are shown. However, the design in this walkthrough is that the package decides at run time whether the command should be visible, based on whether the Media Player tool window is active.

You must first modify FirstToolWin.vsct to enable dynamic visibility, then implement logic to set the visibility in code. You create a class to hold tool window events, then modify the package to make the menu command object accessible, and then tie them together.

To enable dynamic visibility

  1. Open the "FirstToolWin" project, which you created in Walkthrough: Creating a Tool Window (Part 2 of 4).

  2. In Solution Explorer, open FirstToolWin.vsct.

  3. Find the <Button> element that has the ID, cmdidWindowsMedia. Between the <icon> definition and the <Strings> section, add two command flags, as follows.

    <CommandFlag>DefaultInvisible</CommandFlag>
    <CommandFlag>DynamicVisibility</CommandFlag>
    
  4. Save the file.

To create tool window events

  1. In Solution Explorer, right-click the project name, point to Add, and then click Class.

  2. In the Add New Item dialog box, name the file ToolWindowEvents.cs or ToolWindowEvents.vb and then click Add.

  3. Open ToolWindowEvents.cs or ToolWindowEvents.vb and add the following code after any existing using or Imports statements.

    Imports System
    Imports System.Collections.Generic
    Imports System.Linq
    Imports System.Text
    Imports Microsoft.VisualStudio.Shell.Interop
    Imports System.ComponentModel.Design
    Imports System.Security.Permissions
    
    using Microsoft.VisualStudio.Shell.Interop;
    using System.ComponentModel.Design;
    using System.Security.Permissions;
    
  4. Change the class declaration so that it is public and sealed, (Public and NotInheritable in Visual Basic) and inherits from the IVsWindowFrameNotify3 interface, as follows.

    Public NotInheritable Class ToolWindowEvents
        Implements IVsWindowFrameNotify3
    
    public sealed class ToolWindowEvents : IVsWindowFrameNotify3
    
  5. If you are using C#, right-click IVsWindowFrameNotify3, point to Implement Interface, and then click Implement Interface to automatically add the methods that are required for the interface.

    If you are using Visual Basic, skip this step.

  6. Implement the OnShow method, as follows.

    Public Function OnShow(ByVal fShow As Integer) As Integer Implements VisualStudio.Shell.Interop.IVsWindowFrameNotify3.OnShow
        If Not fShow = __FRAMESHOW.FRAMESHOW_WinHidden Then
            package.toolMenuItem1.visible = True
        End If
        Return Microsoft.VisualStudio.VSConstants.S_OK
    End Function
    
    [PrincipalPermission(SecurityAction.Demand)]
    public int OnShow(int fShow)
    {
        package.toolMenuItem1.Visible
            = ((__FRAMESHOW)fShow
            != __FRAMESHOW.FRAMESHOW_WinHidden);
        return Microsoft.VisualStudio.VSConstants.S_OK;
    }
    
  7. Fill in the content of remaining IVsWindowFrameNotify3 interface members by using the following return statement.

    Return Microsoft.VisualStudio.VSConstants.S_OK
    
    return Microsoft.VisualStudio.VSConstants.S_OK;
    

    Warning

    In C#, the interface members will be populated with throw statements, which you must overwrite. In Visual Basic, the functions will empty.

    The added code declares a class that will receive the events for the tool window. The event used here is OnShow, in which the visibility of the menu command is set based on the value that is passed into the event. The value passed in is an enumeration of the type __FRAMESHOW. Although this enumeration has several possible values, in this case, you must test whether it is equal to FRAMESHOW_WinHidden. If it is not equal, then set Visible to true. If it is equal, then set Visible to false.

    However, notice that this code uses a variable named "package." That variable is passed in to the constructor.

  8. Add the following code to the top of the class, above the region where the IVsWindowFrameNotify3 interface members are defined.

    Private package As FirstToolWinPackage
    Public Sub New(ByVal apackage As FirstToolWinPackage)
        package = apackage
    End Sub
    
    private FirstToolWinPackage package;
    public ToolWindowEvents(FirstToolWinPackage apackage)
    {
        package = apackage;
    }
    

    The value passed into this constructor is the package itself, the FirstToolWin instance. In the OnShow event, the menu command must be accessed. By default, this menu command is a locally scoped variable in the Initialize method of the package.

  9. Save the file.

To access the menu command

  1. In Solution Explorer, open FirstToolWinPackage.cs or FirstToolWinPackage.vb so that you can modify the FirstToolWin class to make the menu command object accessible.

  2. Declare a MenuCommand object at the top of the class to represent your menu command.

    Public toolMenuItem1 As MenuCommand
    
    public MenuCommand toolMenuItem1;
    
  3. Scroll to the Initialize method. Locate the following two lines, which create the first command.

    Dim menuItem As New MenuCommand(New EventHandler(AddressOf MenuItemCallback), menuCommandID)
    mcs.AddCommand(menuItem)
    
    MenuCommand menuItem = new MenuCommand(MenuItemCallback, menuCommandID);
    mcs.AddCommand(menuItem);
    
  4. Replace the default MenuCommand object by using the public variable that was declared earlier.

    Dim toolMenuItem1 As New MenuCommand(New EventHandler(AddressOf MenuItemCallback), menuCommandID)
    mcs.AddCommand(toolMenuItem1)
    
    toolMenuItem1 = new MenuCommand(MenuItemCallback, menuCommandID);
    mcs.AddCommand(toolMenuItem1);                
    
  5. Save the file.

Next, you will create an instance of the tool window and also an instance of the newly created class to receive the events. Then you can attach the class instance to the tool window instance.

To attach the events

  1. In Solution Explorer, open MyToolWindow.cs or MyToolWindow.vb. Override the OnToolWindowCreated method by adding the following code at the end of the file, before the closing brace of the class definition.

    Public Overrides Sub OnToolWindowCreated()
        MyBase.OnToolWindowCreated()
    
        Dim handler As FirstToolWinPackage = CType( _
            Me.Package, FirstToolWinPackage)
        CType(Me.Frame, IVsWindowFrame).SetProperty( _
            CInt(__VSFPROPID.VSFPROPID_ViewHelper), handler)
    End Sub
    
    public override void OnToolWindowCreated()
    {
        base.OnToolWindowCreated();
    
        var handler = new ToolWindowEvents(
            (FirstToolWinPackage)this.Package);
        ((IVsWindowFrame)this.Frame).SetProperty(
            (int)__VSFPROPID.VSFPROPID_ViewHelper, handler);
    }
    

    This code creates a new instance of the class that was added earlier. It then adds the instance to the properties of the frame so that the instance can receive events. The SetProperty method accomplishes this when you pass the enumeration value VSFPROPID_ViewHelper for the first parameter, and the new handler instance for the second parameter.

  2. Save the file.

To test the code

  1. Press F5 to compile the project and run it in the experimental build of Visual Studio.

  2. Click the Tools menu.

    The WindowsMedia menu command should not appear.

  3. On the View menu, point to Other Windows and then click Windows Media Player to display the Media Player window.

  4. Click the Tools menu again.

    Now, the WindowsMedia menu command should appear because it has dynamic visibility; that is, whether it is visible is based on whether the Media Player window is visible.

  5. Close the Media Player window and then check the Tools menu again.

    Now, the WindowsMedia menu command should not appear.

  6. Close the experimental build.

Add Windows Forms Code to Interact with the Tool Window

Now, add code to the package class that responds to the menu command. This code opens an Open File dialog box and then calls the new LoadFile method to load a file in the Media Player.

To activate the tool window in code

  1. Open FirstToolWinPackage.cs.

  2. Add the System.Windows.Forms namespace just after the existing using statements, as follows.

    Imports System.Windows.Forms
    
    using System.Windows.Forms;
    
  3. Find the MenuItemCallback menu handler. This is the event handler for a click on the menu command. Replace the body of this menu handler by using the following code.

    Dim openFileDialog As OpenFileDialog = New OpenFileDialog()
    Dim result As DialogResult = openFileDialog.ShowDialog()
    If (result Is DialogResult.OK) Then
        Dim window As MyToolWindow = TryCast(Me.FindToolWindow(GetType(MyToolWindow), 0, True), MyToolWindow)
        If (window Is Not Nothing) Then
            window.LoadFile(openFileDialog.FileName)
        End If
    End If
    
    System.Windows.Forms.OpenFileDialog openFileDialog = new System.Windows.Forms.OpenFileDialog();
    DialogResult result = openFileDialog.ShowDialog();
    if (result == DialogResult.OK)
    {
        MyToolWindow window = (MyToolWindow)(this.FindToolWindow(
            typeof(MyToolWindow), 0, true));
        if (window != null)
        {
            window.LoadFile(openFileDialog.FileName);
        }
    }
    
  4. Save your work.

This code opens an Open File dialog box so that you can browse to the media file that you want to load in the Media Player. Then it locates the MyToolWindow instance and calls the LoadFile method, which you created earlier, to load the media file.

To test the code

  1. Press F5 to compile the project and run it in the experimental instance of Visual Studio.

  2. On the Tools menu, click WindowsMedia.

    The Open File dialog box should appear.

  3. In the Open File dialog box, select a valid media file and then click OK.

    The file should play in the Media Player.

  4. Close the experimental instance.

What's Next

This walkthrough shows how to add menu commands that have dynamic visibility. It also shows how to add controls to a tool window that interact with other controls in the tool window. These concepts apply in general to tool windows. The controls that you add to tool windows closely resemble the user controls that you would use in a Windows Forms application.

In the next walkthrough, Walkthrough: Integrating into the Properties Window, Task List, Output Window, and Options Dialog Box (Part 4 of 4), you can learn how to integrate your tool window together with the existing tool windows in Visual Studio, such as the Properties window, the Output window, and the Task List window.

See Also

Other Resources

Extending Visual Studio Overview