Add Menu Item to a VS extension old ‘Package’ (as opposed to newer ‘AsyncPackage’)

This tutorial relates to the old  Microsoft.VisualStudio.Shell.Package. This should be used for older Visual Studio versions (VS 2013 and older). The Package  is loaded synchronously on the UI thread and can cause responsiveness issues. Synchronous loading of packages will stop being supported in a future version of Visual Studio.

For VS 2015 and later, it’s recommended to use the later AsyncPackage  – see tutorial here.

Add Menu Item to the VS extensions

A menu item is a Command in the Visual Studio extensions world. A Command is a piece of functionality you can add to your extensions. It can be invoked from a menu item, toolbar, context menu or from code.

A Command is a part of VSPackage. VSPackage is defined as a software module that extends Visual Studio. A VSPackage can contain many commands.

Sources: Here’s a detailed tutorial of VSPackage and Command. And here’s the MSDN documentation on adding a menu item.

So first of all, we need to add a VSPackage.

  1. In Solution Explorer add new item from C# Items -> Extensibility -> Visual Studio Package and call it CodyDocsPackage. Several files should’ve been created: CodyDocsPackage.cs, CodyDocsPackage.vsct and CodyDocsPackage.ico in Resources.
  2. The .vsct file created is the Visual Studio Command Table. It’s an XML file that describes the structure of the commands and their initial state.Let’s add the command that enables and disables the feature. In Solution Explorer add new Custom Command with C# Items -> Extensibility -> Custom Command and call it EnableDisableCodyDocsCommand. This will be automatically associated to our VSPackage. If we go to CodyDocsPackage.vsct, we’ll see that the Command was added to the package in <Buttons>.
    If you look at the EnableDisableCodyDocsCommand.cs file created, there will be a method MenuItemCallback. Here you can place any custom code and it will be called whenever the command is invoked.
  3. We need to add a menu item that will invoke our command. This is configurable in the .vsct file. In Solution Explorer, open CodyDocsPackage.vsct. At the end of the file, there is a <Symbols> node that contains several <GuidSymbol> nodes. In the node named guidCodyDocsPackageCmdSet, add a new symbol, as follows:
  4. Create a <Menus> node in the <Commands> node, just before <Groups> as follows:
    “CodyDocs” in the <CommandName> element will be the top level menu caption.
  5. In the <Groups> section, find the <Group> and change the <Parent> element to point to the menu we just added (both guid and id attributes):
  6. Now just find the Button and change the text of our menu item:

Run the extensions. You should see this:

Turn our menu item into a Check box

Now to turn our menu item into a checkbox that enables and disables our setting.

VS includes a functionality to Check and Uncheck a MenuCommand with the Checked property.

In our EnableDisableCodyDocsCommand.cs, change the constructor and the command callback to:

The constructor sets the initial state. The MenuItemCallback will toggle the setting state and update the Command’s Checked value accordingly.

That’s it. Now pressing on the menu item will toggle the icon and will change our EnableCodyDocs setting.

Well, there’s one final touch. Visual studio doesn’t load the Command until first use. Which means, our Command’s constructor won’t be called and our menu item will be in its default state – unchecked, regardless of the setting’s value.

We need to make our Command to initialize at Visual Studio startup. To do that, we need to make our VSPackage to initialize at startup. This is done with the ProvideAutoLoad attribute in the package class file CodyDocsPackage.cs like this: (More on ProvideAutoLoad)

Note that we have the attribute twice: When there’s no Solution, and when Solution exists. Which covers all cases.



Enjoy the blog? I would love you to subscribe! Performance Optimizations in C#: 10 Best Practices (exclusive article)

Want to become an expert problem fixer? Check out a chapter from my book Practical Debugging for .NET Developers