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
Open the "FirstToolWin" project, which you created in Walkthrough: Creating a Tool Window (Part 2 of 4).
In Solution Explorer, open FirstToolWin.vsct.
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>
Save the file.
To create tool window events
In Solution Explorer, right-click the project name, point to Add, and then click Class.
In the Add New Item dialog box, name the file ToolWindowEvents.cs or ToolWindowEvents.vb and then click Add.
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;
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
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.
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; }
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.
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.
Save the file.
To access the menu command
In Solution Explorer, open FirstToolWinPackage.cs or FirstToolWinPackage.vb so that you can modify the FirstToolWin class to make the menu command object accessible.
Declare a MenuCommand object at the top of the class to represent your menu command.
Public toolMenuItem1 As MenuCommand
public MenuCommand toolMenuItem1;
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);
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);
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
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.
Save the file.
To test the code
Press F5 to compile the project and run it in the experimental build of Visual Studio.
Click the Tools menu.
The WindowsMedia menu command should not appear.
On the View menu, point to Other Windows and then click Windows Media Player to display the Media Player window.
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.
Close the Media Player window and then check the Tools menu again.
Now, the WindowsMedia menu command should not appear.
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
Open FirstToolWinPackage.cs.
Add the System.Windows.Forms namespace just after the existing using statements, as follows.
Imports System.Windows.Forms
using System.Windows.Forms;
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); } }
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
Press F5 to compile the project and run it in the experimental instance of Visual Studio.
On the Tools menu, click WindowsMedia.
The Open File dialog box should appear.
In the Open File dialog box, select a valid media file and then click OK.
The file should play in the Media Player.
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.