2

I'm writing a VS2012 add-in, adding a command to Build Explorer context menu (see related question). The command gets added to 2 different context menus:

  1. Build Explorer
  2. Team Explorer, Builds page, My Builds section

When my one callback is called, how do I know which of these it is?

I tried get the focused control (using P/Invoke as this question suggests). However, it gets me a Tabs container for (1), and null for (2). I could try to cast the control to the tabbed container, but that sounds pretty bad...

Any better alternative?

Community
  • 1
  • 1
Jonathan
  • 6,939
  • 4
  • 44
  • 61

2 Answers2

0

Reworked by the comment, and founded links:

As the menu item is shown every place it seems there is no way to distinct between them from an Add-In, you should add two command and distinct them by their context.

The way instead of converting the Add-In to a VS-Package MZ-Tools HOWTO: Controlling the state of command in a Visual Studio add-in, try MZ-Tools HOWTO: Use the IVsMonitorSelection ... you can also get it from an Add-In.

But:

Neither the AddNamedCommand nor the QueryStatus methods honor the invisible state: the button that must be invisible ... remains disabled rather than invisible.

I think this makes it impossible to do it from an Add-In on a suitable way, but maybe you can check the contexts.

Other way you could get further, if you try to migrate your command/menu into a VSPackage and create a custom UIContext for the menu items or find a suitable predefined one. I have no access to a Studio enhanced with Build Explorer so I can't try it.

The following discussion is about custom contexts for vs-packages: http://davedewinter.com/2008/04/05/dynamic-menu-commands-in-visual-studio-packages-part-3/
Sadly the links are broken from the post, and I can't reach Part 1. and Part 2. which is about the discussion of the problem from the beginning. But there is no guarantee you can create a context which suits you.

Only context ID I found for Team Explorer is the guidTeamProjectCmdUIContext. It is placed at vsshilds.h in Visual Studio 2010 SDK, vsshell*.h are also contain several others.

MSDN: Vsct files to define command, menus, ect. from packages.

Condition attribute for items:
http://msdn.microsoft.com/en-us/library/bb491718.aspx
http://msdn.microsoft.com/en-us/library/bb166515.aspx

MSDN: VisibilityItem element for commands and toolbars.

VisibilityItem element determines the static visibility of commands and toolbars. ... After the VSPackage is loaded, Visual Studio expects command visibility to be determined by the VSPackage rather than the VisibilityItem.

And finally about predefined Context Guids:
http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.shell.interop.uicontextguids80.aspx
http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.shell.interop.uicontextguids.aspx

Ursegor
  • 878
  • 8
  • 16
  • This does not apply here: When I add my command, it automatically appears in both places, and AFAIK there's no way to tell the command to appear only in one. It kind of makes sense - these are 2 places that VS displays the exact same items, so the commands relevant to the items should appear in both places. – Jonathan Dec 24 '13 at 09:05
  • If you add a menu Item for a context menu like Solution, it is not sure you want to use it in every circumstances. For example Tfs commands are invisible on a simple solution. But If you want to distinct between statets of the `UI` or your own program, this seems to be the proper way for it. You should try it with a simple package, and get the available `UI GIUID`s. – Ursegor Dec 26 '13 at 09:04
0

My new/other idea - it is similar to yours:

You should try to monitor which window was activated lastly.

If you create an eventhandler for your command, then you may be able to check which window is active when your command fired. A simple evenent handler for a command:

void cmdEvents_BeforeExecute( string guid, int ID, object customIn, object customOut, ref bool cancelDefault )
{
  Window2 teamExplorer = _applicationObject.Windows.Item("Team Explorer") as Window2;
  if (_applicationObject.ActiveWindow.Caption == teamExplorer.Caption)
  {
       //You are called from Team Explorer
  }
  else
  {
       //Somewhere else
  }
}

And the way you can subscribe:

static _dispCommandEvents_BeforeExecuteEventHandler _myHandler;
static CommandEvents _cmdEvents;

public void OnConnection(...)
{
   Command command = ...; // Init your command 
   int ID = command.ID;
   string GUID = command.Guid;

   CommandEvents _cmdEvents = _applicationObject.Events.get_CommandEvents(GUID, ID);

   _myHandler = new _dispCommandEvents_BeforeExecuteEventHandler(cmdEvents_BeforeExecute);

   _cmdEvents.BeforeExecute += _myHandler;
}

You may find a better way to identify the window(s) by GUID. You should keep at least _cmdEvents as static because when it will be desroyed, your event handler could vanish (least for internal commands).

In OnDisconnection you should unsubscribe.

Ursegor
  • 878
  • 8
  • 16