Apr 5, 2009

Visual Studio - Writing a Add-In (plugin) with context menus

The following example demonstrates how to write a plug-in, clicking on which pops up a context menus with menu items as show in the figure




Follow the steps mentioned in the post to write a simple plugin 'Demo'. Create a new file 'MyMenuItem.cs' with the following content.


using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace MyAddin1
{
internal class MyMenuItem : MenuItem
{
public MyMenuItem(String name)
: this(name, name, null, 0)
{
}

public MyMenuItem(String name, String text, EventHandler eh, int id)
: base(text, eh)
{
m_name = name;
m_id = id;
}

public String MenuName
{
get { return m_name; }
set { m_name = value; }
}

public int MyMenuID
{
get{ return m_id; }
}

private String m_name;
private int m_id;
}
}



Add another file 'MyMenu.cs'

using System;
using System.Collections.Generic;
using System.Text;

using System.Windows.Forms;
using System.Collections;

namespace MyAddin1
{
internal class MyMenu : ContextMenu
{
public MyMenu()
{
m_stackMenu = new Stack();
m_stackMenu.Push(MenuItems);
}

public Menu.MenuItemCollection CurrentMenu
{
get { return (Menu.MenuItemCollection)m_stackMenu.Peek(); }
}

public void Add(String name, String text, int id)
{
CurrentMenu.Add(new MyMenuItem(name, text, m_eh, id));
}

public void PopAll()
{
m_stackMenu.Clear();
m_stackMenu.Push(MenuItems);
}

public void PopMenu()
{
m_stackMenu.Pop();
}

public MyMenuItem PushMenu(String name, EventHandler eh)
{
m_menuitem = new MyMenuItem(name, name, eh, 0);
CurrentMenu.Add(m_menuitem);
m_stackMenu.Push(m_menuitem.MenuItems);
return m_menuitem;
}

public EventHandler EventHandler
{
get { return m_eh; }
set { m_eh = value; }
}

private Stack m_stackMenu;
private EventHandler m_eh;
private MyMenuItem m_menuitem;
}
}



Modify the OnConnection method in the file Connect.cs to make the add-in visible in the 'MenuBar' at the position 1

public void OnConnection(object application, ext_ConnectMode connectMode,
object addInInst, ref Array custom)
{
_applicationObject = (DTE2)application;
_addInInstance = (AddIn)addInInst;
if(connectMode == ext_ConnectMode.ext_cm_UISetup)
{
object[] contextGUIDS = new object[] { };
Commands2 commands = (Commands2)_applicationObject.Commands;
CommandBar bar = ((CommandBars)_applicationObject.CommandBars)["MenuBar"];

try

{
Command command = commands.AddNamedCommand2(
_addInInstance, "MyAddin1", "Demo", "Do Something", true, 59,
ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported +
(int)vsCommandStatus.vsCommandStatusEnabled,
(int)vsCommandStyle.vsCommandStylePictAndText,
vsCommandControlType.vsCommandControlTypeButton);

//Add a control for the command to the tools menu:

if(command != null)
{
command.AddControl(bar, 1);
}
}
catch(System.ArgumentException){
}
}
}



Modify Exec() method which executes whenever the command is invoked

public void Exec(string commandName, vsCommandExecOption executeOption,
ref object varIn, ref object varOut, ref bool handled)
{
handled = false;
if(executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)
{
if(commandName == "MyAddin1.Connect.MyAddin1")
{
ShowMenu();
handled = true;
return;
}
}
}





The ShowMenu() lists the down how the context menu structure should look like

private void ShowMenu()
{
Point pt;

try
{
CommandBar bar = ((CommandBars)_applicationObject.CommandBars)["Demo"];
CommandBarControl control = bar.Controls[1];
pt = new Point(control.Left, control.Top);
}
catch(Exception){
pt = Control.MousePosition;
}

Control window = new Control();
window.CreateControl();

MyMenu menu = new MyMenu();
// Register event handler with MyMenu

menu.EventHandler = new EventHandler(this.OnClick);

menu.PushMenu("GroupOne", menu.EventHandler);
menu.PushMenu("GroupOneMenu", menu.EventHandler);
menu.PopMenu();
menu.PopMenu();

menu.PushMenu("GroupTwo", menu.EventHandler);
menu.PushMenu("GroupTwoMenu", menu.EventHandler);
menu.PopMenu();
menu.PopMenu();

menu.PushMenu("GroupThree", menu.EventHandler);
menu.PushMenu("GroupThreeMenu1", menu.EventHandler);
menu.PushMenu("GroupThreeMenu2", menu.EventHandler);
menu.PushMenu("GroupThreeMenu3", menu.EventHandler);
menu.PopAll(); // either call PopMenu() 4 times or PopAll()

menu.Add("MenuItem1", "MenuItem1", -1);
menu.Add("MenuItem2", "MenuItem2", -2);
menu.Add("AboutDemo", "AboutMenu", -3);

menu.Show(window, pt); //displays context menu

}




Handling Click events on MenuItems

private void OnClick(Object sender, EventArgs e)
{
try
{
MyMenuItem mi = (MyMenuItem)sender;
MessageBox.Show("Hello from " + mi.MenuName);
}
catch(Exception ex){
MessageBox.Show(ex.Message, ex.Source);
}
}




Now select the Menu Item from the GroupThree




You see a message box with the message 'Hello from GroupThreeMenu3'



Your plugin is working as expected. Cheers !! :)

No comments :

Post a Comment