The previous blog post introduced the wonderful world of Visual Studio extensions.
Let’s start and do some coding. During the tutorial we are going to build a VS extensions called CodyDocs and place it on GitHub.
CodyDocs will save code documentation in a separate file and the extension will allow to view and edit the documentation in the editor itself.
In the first part, we’ll start with a simple “Hello World” program. We’ll create an extensions with a Menu item that does something. I’ll make things a bit more interesting and make the menu item act as a checkbox.
Starting the project
A great way to start any feature is to add a button to disable it. So first order of business: Add a checkable menu item to Enable and Disable the feature our extension performs.
First, we’ll create a new project with File -> New Project -> VSIX project and call it CodyDocs.
Now to be able to enable and disable the feature, we need the ability to store a bool value that stores our setting.
Create a Settings file
A settings file is where you can save your application and user settings (Very much like app.config). We can add one such item by Right clicking on project -> New Item. Then Visual C# Items -> General -> Settings File. Let’s call it GeneralSettings.
In the designer we add a new setting:
We can now get or set this option with GeneralSettings.Default.EnableCodyDocs.
Next, I want a menu item to be able to toggle this setting.
Add Menu item to the VS extension
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.
- 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.
- 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.
- 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:
1<IDSymbol name="TopLevelMenu" value="0x1021"/>
- Create an empty <Menus> node in the <Commands> node, just before <Groups>. In the <Menus> node, add a <Menu> node , as follows:
12345678910<Menus><Menu guid="guidCodyDocsPackageCmdSet" id="TopLevelMenu" priority="0x700" type="Menu"><Parent guid="guidSHLMainMenu"id="IDG_VS_MM_TOOLSADDINS" /><Strings><ButtonText>TestMenu</ButtonText><CommandName>CodyDocs</CommandName></Strings></Menu></Menus>
- In the <Groups> section, find the <Group> and change the <Parent> element to point to the menu we just added:
12345<Groups><Group guid="guidCodyDocsPackageCmdSet" id="MyMenuGroup" priority="0x0600"><Parent guid="guidCodyDocsPackageCmdSet" id="TopLevelMenu"/></Group></Groups>
- Now just find the Button and change the text of our menu item:
12345789<Buttons><Button guid="guidCodyDocsPackageCmdSet" id="EnableDisableCodyDocsCommandId" priority="0x0100" type="Button"><Parent guid="guidCodyDocsPackageCmdSet" id="MyMenuGroup" /><Icon guid="guidImages" id="bmpPic1" /><Strings></Strings></Button></Buttons>
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:
private EnableDisableCodyDocsCommand(Package package)
if (package == null)
throw new ArgumentNullException("package");
this.package = package;
OleMenuCommandService commandService =
this.ServiceProvider.GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
if (commandService != null)
var menuCommandID = new CommandID(CommandSet, CommandId);
var command = new MenuCommand(this.MenuItemCallback, menuCommandID);
private void MenuItemCallback(object sender, EventArgs e)
var command = sender as MenuCommand;
command.Checked = GeneralSettings.Default.EnableCodyDocs;
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)
[PackageRegistration(UseManagedResourcesOnly = true)]
[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)] // Info on this package for Help/About
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly", Justification = "pkgdef, VS and vsixmanifest are valid VS terms")]
public sealed class CodyDocsPackage : Package
Note that we have the attribute twice: When there’s no Solution, and when Solution exists. Which covers all cases.
We created a simple extensions with a check-able Menu item. For that, we created VSPackage and a Command part of that package.
That’s a pretty simple “Hello World!” intro to VS extensibility. I promise we’ll dig in into much more difficult and interesting stuff.
In the next tutorial we’ll start working on the core functionality of the extension: Highlight a piece of code in the editor and add the documentation.
The source code is available on GitHub, with Tag Part2. So to clone and checkout to specific tag, write:
> git clone https://github.com/michaelscodingspot/CodyDocs.git
> git checkout tags/Part2
Tutorial Table of Contents:
Part 1: Introduction to VS extensibility
Part 2: Add Menu Item (You are here)
Part 3: Add command to context menu and get selected code