An ADR Visual Studio Tool – Part 7 – Adding a Context Menu Item

March 28, 2020

In my previous post I continued with my little series on writing an extension for Visual Studio by completing the functionality to view existing ADRs within the solution. You can see the first post here

In this post, we’ll cover the process of adding a command to the solution and project context menu. Having completed the screen that will show existing ADRs, we now want to allow the user to right-click on a project or solution and select to add a new ADR:

adr 7 1

The first step is to add the command; fortunately, this is a pre-made template, so just select to add a new item (ironically), and pick Command:

adr 7 2

This will create you a menu item that will appear under the Tools menu by default, and will display a message box when selected:

adr 7 3

There are two things that we need to change about this command: the text (we don’t want it to read “Invoke AddAdrCommand”), and the location (we want it to be available from the right-click context menu of a project). Both of those things are changed in the file AdrPackage.vsct (if your project is called Aardvark, this will be named AardvarkPackage.vsct).

If you have a look in that file, you’ll see something called MyMenuGroup; which is referenced in three places. The first defines what it is:

adr 7 4

This is where you can change the command text (as I have above).

The second, where it is:

adr 7 5

This initially looks like this:

<Parent guid="guidSHLMainMenu" id="IDM\_VS\_MENU\_TOOLS" />

Which adds the menu to the top level Tools menu; change it to:

<Parent guid="guidSHLMainMenu" id="IDM\_VS\_CSCD\_PROJECT\_ADD" />

As I have.

There are other options here.

The third is the ID Symbol:

adr 7 6

If you decide to change the name of MyMenuGroup, you will need to do so in all three places above.

Getting the Context of the Current Project

Now that we’ve moved the menu to the context menu, we’ll need to find which project we’re in by accessing the DTE Service - this is retrieved by calling the command:

            var dte = await package.GetServiceAsync(typeof(DTE)).ConfigureAwait(false) as DTE2;

You can then find out what’s selected by accessing the selected hierarchy:

            UIHierarchy uih = (UIHierarchy)dte.Windows.Item(
            Array selectedItems = (Array)uih.SelectedItems;

Here’s the full code of the Execute method, to display the selected project:

        private async void Execute(object sender, EventArgs e)
            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken);

            var dte = await package.GetServiceAsync(typeof(DTE)).ConfigureAwait(false) as DTE2;

            UIHierarchy uih = (UIHierarchy)dte.Windows.Item(
            Array selectedItems = (Array)uih.SelectedItems;
            foreach (UIHierarchyItem selectedItem in selectedItems)
                // Show a message box to prove we were here
                    "Selected Project",

We’re not far off now - there’s a few little issues, but the main thing that’s left is that we’re not actually adding anything - just displaying a message. The next step is to get it to actually add a file, but we’ll come to that in the next post.

The code for this project can be found here.


Profile picture

A blog about one man's journey through code… and some pictures of the Peak District

© Paul Michaels 2024