Sunday, January 24, 2010

Visual Studio CommandBars and Commands

This blog is about Visual Studio Extensibility. Recently I was at the task of providing my own menuitems in the Visual Studio and catching the events generated by default Visual Studio toolbar buttons.

In Visual Studio Extensibility api DTE / DTE2 are the application objects through which we can access the Visual Studio CommandBars like Tools,File, Edit etc. Add-In,Vba, Vsta developers are probably familar with the DTE/DTE2 application object. DTE not only provide access to the commandbars but whole set of Visual Studio features.

We can access the solution opened in the VS, we can access projects in the solution and there properties.We can set debug paths, reference paths , project types and all lots of thing.

But this blog is about CommandBars and Commands. CommandBar object is the main menu that is in VS like Tools, Debug, File etc, then there is CommandBar Controls and CommandBar buttons which are the menuitem for the main menu. To access the CommandBars we should have the application object DTE. It is provided as a parameter (object application) in OnConnection method of the Add-In project.

public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
{
}

It can also be accessed in VSTA through :

IDTEProvider provider = (IDTEProvider)new VSTADTEProviderClass();
EnvDTE.DTE _dte = (EnvDTE.DTE)provider.GetDTE("HostName", 0);

Now we have our DTE object , we can start accessing the CommandBars of Visual Studio. DTE object exposes the CommandBars property that contains the list of all avialable Command Bars within the VS. Lets get the Tools Command Bar.

CommandBars commandBars = this._dte.CommandBars as CommandBars;
CommandBar toolsMenuBar = ((CommandBars)this._dte.CommandBars)["Tools"];

Adding the Command Bar button to the Tools CommandBar is simple , just call the CommandBar.Controls.Add method with right parameters, this will return CommandBarControl object and now cast the CommandBarControl in the CommandBarButton. CommandBarButton have many properties that we can set, some of useful ones are set in the following code.

Where to set the CommandBar Button, is it temporary, its type (PopUp, DropDown) all can be set by the parameters passed on to the Add method.

CommandBarControl myControl = toolsMenuBar.Controls.Add (MsoControlType.msoControlButton, 1, "", 4, true);
CommandBarButton myButton = reloadControls as CommandBarButton;
myButton ols.Caption = "My Button"; // Menuitem name
myButton .Visible = true; //Visible property
myButton .BeginGroup = true; // Gets the seperator for menuitem
myButton .FaceId = 0319; // icon to show
myButton .Enabled = false; // Enabled
property.

Now we can bind a event handler to this custom CommandBar Button and perform our custom action.
myButton.Click += new _CommandBarButtonEvents_ClickEventHandler(myButton_Click);

The default buttons of VS, on there click perform certain actions like opening New Project Dialog, Open Dialog etc. These actions are invoked by the Visual Studio Commands which are in turn invoked by click event of CommandBarButtons.
Commands are not the UI elements but way by which VS execute particular action.
To get the events of these commands we should know the GUID and ID of the VS Commands.

EnvDTE.CommandEvents newProjectEvents = this._dte.Events.get_CommandEvents("{5EFC7975-14BC-11CF-9B2B-00AA00573819}", 216);

How to get these Guid's and Id's ?. We can loop through DTE.Commands collection to find our Command and Guid,Id associated with it.

internal void FindGuid()
{
string commandName = String.Empty;
string commandGuidNewProject = String.Empty;
string commandGuidOpenProject = String.Empty;
int commandIdOpenProject = 0;
int commandIdNewProject = 0;
EnvDTE.Command command;
for(int i = 1; i < m_dte.Commands.Count; i++)
{
command = m_dte.Commands.Item(i, i);
commandName = command.Name;
if(commandName == "File.NewProject")
{
commandGuidNewProject = command.Guid.ToString();
commandIdNewProject = command.ID;
}
if(commandName == "File.OpenProject")
{
commandGuidOpenProject = command.Guid.ToString();
commandIdOpenProject = command.ID;
}
}
}

The CommandEvents that we accessed through the Guid /Id of VS command have many events with which we can bind our event handlers. Events which we are interested in are AfterExecute and BeforeExecute, these are fired after and prior to the execution of the Command action.

newProjectEvents.BeforeExecute+= new _dispCommandEvents_BeforeExecuteEventHandler(newProjectEvents_BeforeExecute);

newProjectEvents.AfterExecute += new _dispCommandEvents_AfterExecuteEventHandler(newProjectEvents_AfterExecute);

We have seen how to add our cutom command bar button , bind its click event and how to bind to the events of VS Commands.Hope you will find something useful out of this blog.


1 comment:

  1. What an interesting and explicit post, I am searching for guides on CommandBar control but didn't find a good one. This passage helps me a lot!

    ReplyDelete