Adding a Shortcut Menu in a Tool Window
Note
This article applies to Visual Studio 2015. If you're looking for the latest Visual Studio documentation, see Visual Studio documentation. We recommend upgrading to the latest version of Visual Studio. Download it here
This walkthrough puts a shortcut menu in a tool window. A shortcut menu is a menu that appears when a user right-clicks a button, text box, or window background. Commands on a shortcut menu behave the same as commands on other menus or toolbars. To support a shortcut menu, specify it in the .vsct file and display it in response to the right-click of the mouse.
A tool window consists of a WPF user control in a custom tool window class that inherits from ToolWindowPane.
This walkthrough shows how to create a shortcut menu as a Visual Studio menu, by declaring menu items in the .vsct file, and then using the Managed Package Framework to implement them in the class that defines the tool window. This approach facilitates access to Visual Studio commands, UI elements, and the Automation object model.
Alternatively, if your shortcut menu will not access Visual Studio functionality, you can use the ContextMenu property of a XAML element in the user control. For more information, see ContextMenu.
Prerequisites
Starting in Visual Studio 2015, you do not install the Visual Studio SDK from the download center. It is included as an optional feature in Visual Studio setup. You can also install the VS SDK later on. For more information, see Installing the Visual Studio SDK.
Creating the Tool Window Shortcut Menu Package
- Create a VSIX project named
TWShortcutMenu
and add a tool window template named ShortCutMenu to it. For more information about creating a tool window, see Creating an Extension with a Tool Window.
Specifying the Shortcut Menu
A shortcut menu such as the one shown in this walkthrough lets the user select from a list of colors that are used to fill the background of the tool window.
In ShortcutMenuPackage.vsct, find in the GuidSymbol element named guidShortcutMenuPackageCmdSet, and declare the shortcut menu, shortcut menu group, and menu options. The GuidSymbol element should now look like this:
<GuidSymbol name="guidShortcutMenuPackageCmdSet" value="{00000000-0000-0000-0000-0000}"> // your GUID here <IDSymbol name="ShortcutMenuCommandId" value="0x0100" /> <IDSymbol name="ColorMenu" value="0x1000"/> <IDSymbol name="ColorGroup" value="0x1100"/> <IDSymbol name="cmdidRed" value="0x102"/> <IDSymbol name="cmdidYellow" value="0x103"/> <IDSymbol name="cmdidBlue" value="0x104"/> </GuidSymbol>
Just before the Buttons element, create a Menus element and then define the shortcut menu in it.
<Menus> <Menu guid="guidShortcutMenuPackageCmdSet" id="ColorMenu" type="Context"> <Strings> <ButtonText>Color change</ButtonText> <CommandName>ColorChange</CommandName> </Strings> </Menu> </Menus>
A shortcut menu does not have a parent because it is not part of a menu or toolbar.
Create a Groups element with a Group element that contains the shortcut menu items, and associate the group with the shortcut menu.
<Groups> <Group guid="guidShortcutMenuPackageCmdSet" id="ColorGroup"> <Parent guid="guidShortcutMenuPackageCmdSet" id="ColorMenu"/> </Group> </Groups>
In the Buttons element, define the individual commands that will appear on the shortcut menu. The Buttons element should look like this:
<Buttons> <Button guid="guidShortcutMenuPackageCmdSet" id="ShortcutMenuCommandId" priority="0x0100" type="Button"> <Parent guid="guidSHLMainMenu" id="IDG_VS_WNDO_OTRWNDWS1"/> <Icon guid="guidImages" id="bmpPic1" /> <Strings> <ButtonText>ShortcutMenu</ButtonText> </Strings> </Button> <Button guid="guidShortcutMenuPackageCmdSet" id="cmdidRed" priority="1" type="Button"> <Parent guid="guidShortcutMenuPackageCmdSet" id="ColorGroup" /> <Strings> <ButtonText>Red</ButtonText> </Strings> </Button> <Button guid="guidShortcutMenuPackageCmdSet" id="cmdidYellow" priority="3" type="Button"> <Parent guid="guidShortcutMenuPackageCmdSet" id="ColorGroup" /> <Strings> <ButtonText>Yellow</ButtonText> </Strings> </Button> <Button guid="guidShortcutMenuPackageCmdSet" id="cmdidBlue" priority="5" type="Button"> <Parent guid="guidShortcutMenuPackageCmdSet" id="ColorGroup" /> <Strings> <ButtonText>Blue</ButtonText> </Strings> </Button> </Buttons>
In ShortcutMenuPackageGuids.cs, add the definitions for the command set GUID, the shortcut menu, and the menu items.
public const string guidShortcutMenuPackageCmdSet = "00000000-0000-0000-0000-00000000"; // your GUID will differ public const int ColorMenu = 0x1000; public const int cmdidRed = 0x102; public const int cmdidYellow = 0x103; public const int cmdidBlue = 0x104;
These are the same command IDs that are defined in the Symbols section of the ShortcutMenuPackage.vsct file. The context group is not included here because it is required only in the .vsct file.
Implementing the Shortcut Menu
This section implements the shortcut menu and its commands.
In ShortcutMenu.cs, the tool window can get the menu command service, but the control it contains cannot. The following steps show how to make the menu command service available to the user control.
In ShortcutMenu.cs, add the following using statements:
using Microsoft.VisualStudio.Shell; using System.ComponentModel.Design;
Override the tool window’s Initialize() method to get the menu command service and add the control, passing the menu command service to the contructor:
protected override void Initialize() { commandService = (OleMenuCommandService)GetService(typeof(IMenuCommandService)); Content = new ShortcutMenuControl(commandService); }
In the ShortcutMenu tool window constructor, remove the line that adds the control. The constructor should now look like this:
public ShortcutMenu() : base(null) { this.Caption = "ShortcutMenu"; this.BitmapResourceID = 301; this.BitmapIndex = 1; }
In ShortcutMenuControl.xaml.cs, add a private field for the menu command service and change the control constructor to take the menu command service. Then use the menu command service to add the context menu commands. The ShortcutMenuControl constructor should now look like the following code. The command handler will be defined later.
public ShortcutMenuControl(OleMenuCommandService service) { this.InitializeComponent(); commandService = service; if (null !=commandService) { // Create an alias for the command set guid. Guid guid = new Guid(ShortcutMenuPackageGuids.guidShortcutMenuPackageCmdSet); // Create the command IDs. var red = new CommandID(guid, ShortcutMenuPackageGuids.cmdidRed); var yellow = new CommandID(guid, ShortcutMenuPackageGuids.cmdidYellow); var blue = new CommandID(guid, ShortcutMenuPackageGuids.cmdidBlue); // Add a command for each command ID. commandService.AddCommand(new MenuCommand(ChangeColor, red)); commandService.AddCommand(new MenuCommand(ChangeColor, yellow)); commandService.AddCommand(new MenuCommand(ChangeColor, blue)); } }
In ShortcutMenuControl.xaml, add a MouseRightButtonDown event to the top level UserControl element. The XAML file should now look like this:
<UserControl x:Class="TWShortcutMenu.ShortcutMenuControl" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="https://schemas.microsoft.com/expression/blend/2008" Background="{DynamicResource VsBrush.Window}" Foreground="{DynamicResource VsBrush.WindowText}" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" Name="MyToolWindow" MouseRightButtonDown="MyToolWindow_MouseRightButtonDown"> <Grid> <StackPanel Orientation="Vertical"> <TextBlock Margin="10" HorizontalAlignment="Center">ShortcutMenu</TextBlock> </StackPanel> </Grid> </UserControl>
In ShortcutMenuControl.xaml.cs, add a stub for the event handler.
private void MyToolWindow_MouseRightButtonDown(object sender, MouseButtonEventArgs e) { . . . }
Add the following using statements to the same file:
using Microsoft.VisualStudio.Shell; using System.ComponentModel.Design; using System; using System.Windows.Input; using System.Windows.Media;
Implement the
MyToolWindowMouseRightButtonDown
event as follows.private void MyToolWindow_MouseRightButtonDown(object sender, MouseButtonEventArgs e) { if (null != commandService) { CommandID menuID = new CommandID( new Guid(ShortcutMenuPackageGuids.guidShortcutMenuPackageCmdSet), ShortcutMenuPackageGuids.ColorMenu); Point p = this.PointToScreen(e.GetPosition(this)); commandService.ShowContextMenu(menuID, (int)p.X, (int)p.Y); } }
This creates a CommandID object for the shortcut menu, identifies the location of the mouse click, and opens the shortcut menu in that location by using the ShowContextMenu method.
Implement the command handler.
private void ChangeColor(object sender, EventArgs e) { var mc = sender as MenuCommand; switch (mc.CommandID.ID) { case ShortcutMenuPackageGuids.cmdidRed: MyToolWindow.Background = Brushes.Red; break; case ShortcutMenuPackageGuids.cmdidYellow: MyToolWindow.Background = Brushes.Yellow; break; case ShortcutMenuPackageGuids.cmdidBlue: MyToolWindow.Background = Brushes.Blue; break; } }
In this case, just one method handles events for all of the menu items by identifying the CommandID and setting the background color accordingly. If the menu items had contained unrelated commands, you would have created a separate event handler for each command.
Testing the Tool Window Features
Build the project and start debugging. The experimental instance appears.
In the experimental instance, click View / Other Windows, and then click ShortcutMenu. Doing this should display your tool window.
Right-click in the body of the tool window. A shortcut menu that has a list of colors should be displayed.
Click a color on the shortcut menu. The tool window background color should be changed to the selected color.