locked
Visual Studio ADDIN- adding context menu to Project and determining if selected RRS feed

  • Question

  • Hi,

    I have two problems i need some advice on with my Visual Studio Add-in project.

    1. I have an add-in that adds a custom popup context menu to the following items in Solution Explorer: Solution, Folder, and Item.  I do this by retrieving CommandBars "Solution", "Folder" and "Item", and adding my custom context menu under there.
    I am having problems however adding the context menu to the Project node.  I have tried retreiving the "Project" commandbar and adding the menu there, but it does not show when i run the add-in.  I have also iterated through all commandbars and added the custom menu to any commandbar with the word "Project" in its name...but still my custom menu refuses to show up for the solution explorer's project nodes.  Is there a name for this node that i am missing?

    2.  My second issue is i am not sure how to identify whether the Solution or Project node is selected definitively.  I can do this fine with the Folder and Item nodes, by checking:

    SelectedItem.ProjectItem.Kind == EnvDTE.Constants.vsProjectItemKindPhysicalFolder
    
    SelectedItem.ProjectItem.Kind == EnvDTE.Constants.vsProjectItemKindPhysicalFile

    But i'm not able to do the same for Solution and Project effectively.  This is because for both, SelectedItem.ProjectItem is null and when the Solution node is selected, SelectedItem.Project is also null, where as when the Project node is selected, it is not.  I have actually implemented something that works, but i feel it is probably not the best way to do this since it is sort of guessing based on whether SelectedItem.ProjectItem and or SelectedItem.Project is null (essentially if both are null, i assume the solution node in solution explorer is seleted, and if  SelectedItem.ProjectItem is null but SelectedItem.Project is not, i assume the Project node in solution explorer is selected).

    Any advice and solutions you can offer regarding these issues would be appreciated.

    Wednesday, September 1, 2010 7:42 PM

Answers

  • Hi Mark,

     

    Thanks for your patience.

    If you'd like to add different command when you click on different node in solution explorer, I suggest to add CommandBarPopup on these controls.

    I've tried and managed to make it work.

    Could you please try the walkthrough below

    http://msdn.microsoft.com/en-us/library/90855k9f(VS.100).aspx

    And change the following part:

    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 SECommandBar = ((CommandBars)_applicationObject.CommandBars)["Context Menus"];

                    CommandBarPopup SEPopUps = (CommandBarPopup)SECommandBar.Controls["Project and Solution Context Menus"];

                    CommandBarPopup ProjectPopUp = (CommandBarPopup)SEPopUps.Controls["Project"];

                    CommandBarPopup SolutionPopUp = (CommandBarPopup)SEPopUps.Controls["Solution"];

                    CommandBarPopup ReferencePopUp = (CommandBarPopup)SEPopUps.Controls["Reference Root"];

                    CommandBarPopup ItemPopUp = (CommandBarPopup)SEPopUps.Controls["Item"];

                    //You also can add command to "Folder" "Reference Item"

                    try

                    {

                        Command command = commands.AddNamedCommand2(_addInInstance,

             "ProjCmd", "ProjCmd", "Executes the command for test", true, 59, ref contextGUIDS,

             (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled,

             (int)vsCommandStyle.vsCommandStylePictAndText,

             vsCommandControlType.vsCommandControlTypeButton);

                        Command command1 = commands.AddNamedCommand2(_addInInstance,

             "SolutionCmd", "SolutionCmd", "Executes the command for test", true, 59, ref contextGUIDS,

             (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled,

             (int)vsCommandStyle.vsCommandStylePictAndText,

             vsCommandControlType.vsCommandControlTypeButton);

                        //You can add more command to different controls.

     

                        command.AddControl(ProjectPopUp.CommandBar, 1);

                        command1.AddControl(SolutionPopUp.CommandBar, 1);

                        command.AddControl(ReferencePopUp.CommandBar, 1);

                        command1.AddControl(ItemPopUp.CommandBar, 1);

                    }

                    catch (System.ArgumentException)

                    {

                    }

                }

            }

    public void QueryStatus(string commandName, vsCommandStatusTextWanted

              neededText, ref vsCommandStatus status, ref object commandText)

            {

                if (neededText ==

                  vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)

                {

                    if (commandName == "MyAddin9.Connect.ProjCmd")

                    {

                        status = (vsCommandStatus)vsCommandStatus.

                          vsCommandStatusSupported | vsCommandStatus.

                          vsCommandStatusEnabled;

                        return;

                    }

                    else if (commandName == "MyAddin9.Connect.SolutionCmd")

                    {

                        status = (vsCommandStatus)vsCommandStatus.

                          vsCommandStatusSupported | vsCommandStatus.

                          vsCommandStatusEnabled;

                        return;

                    }

                }

            }

    public void Exec(string commandName, vsCommandExecOption executeOption,

              ref object varIn, ref object varOut, ref bool handled)

            {

                handled = false;

                if (executeOption ==

                  vsCommandExecOption.vsCommandExecOptionDoDefault)

                {

                    if (commandName == "MyAddin9.Connect.ProjCmd")

                    {

                        handled = true;

                        return;

                    }

                    else if (commandName == "MyAddin9.Connect.SolutionCmd")

                    {

                        handled = true;

                        return;

                    }

                }

            }

    I didn’t find document about the controls enumeration, so please reference the picture:

    Hope this can help.

     

    Best Regards,

    Ziwei Chen

     

     

    • Proposed as answer by Victor_Chen Thursday, September 9, 2010 2:16 AM
    • Marked as answer by mark010101 Thursday, September 9, 2010 4:16 PM
    Thursday, September 9, 2010 2:16 AM

All replies

  • Hi Mark,

     

    Thanks for your posting. We are following up with development teams and will get back to you soon.

     

    Best Regards,

    Ziwei Chen

     

    Tuesday, September 7, 2010 3:47 AM
  • Thanks much.  Please let me know if you have any additional info that might help
    Wednesday, September 8, 2010 2:11 PM
  • Hi Mark,

    Different context menus are used when the selection spans multiple items. I'm not sure you can retrieve these via the automation model. Meaning, I haven't actually tried it in recent history :-)

    As an alternative, you could try using the EnableVSIPLogging registry key to identify the guid:id pair that uniquely identifies the context menu:

       see Using EnableVSIPLogging to identify menus and commands for details.

    Then use IVsProfferCommands to retreive the CommandBar object that represents the context menu.

       see Using IVsProfferCommands to retrieve a Visual Studio CommandBar for details.

    Sincerely,


    Ed Dore
    Wednesday, September 8, 2010 6:34 PM
  • Hi Mark,

     

    Thanks for your patience.

    If you'd like to add different command when you click on different node in solution explorer, I suggest to add CommandBarPopup on these controls.

    I've tried and managed to make it work.

    Could you please try the walkthrough below

    http://msdn.microsoft.com/en-us/library/90855k9f(VS.100).aspx

    And change the following part:

    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 SECommandBar = ((CommandBars)_applicationObject.CommandBars)["Context Menus"];

                    CommandBarPopup SEPopUps = (CommandBarPopup)SECommandBar.Controls["Project and Solution Context Menus"];

                    CommandBarPopup ProjectPopUp = (CommandBarPopup)SEPopUps.Controls["Project"];

                    CommandBarPopup SolutionPopUp = (CommandBarPopup)SEPopUps.Controls["Solution"];

                    CommandBarPopup ReferencePopUp = (CommandBarPopup)SEPopUps.Controls["Reference Root"];

                    CommandBarPopup ItemPopUp = (CommandBarPopup)SEPopUps.Controls["Item"];

                    //You also can add command to "Folder" "Reference Item"

                    try

                    {

                        Command command = commands.AddNamedCommand2(_addInInstance,

             "ProjCmd", "ProjCmd", "Executes the command for test", true, 59, ref contextGUIDS,

             (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled,

             (int)vsCommandStyle.vsCommandStylePictAndText,

             vsCommandControlType.vsCommandControlTypeButton);

                        Command command1 = commands.AddNamedCommand2(_addInInstance,

             "SolutionCmd", "SolutionCmd", "Executes the command for test", true, 59, ref contextGUIDS,

             (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled,

             (int)vsCommandStyle.vsCommandStylePictAndText,

             vsCommandControlType.vsCommandControlTypeButton);

                        //You can add more command to different controls.

     

                        command.AddControl(ProjectPopUp.CommandBar, 1);

                        command1.AddControl(SolutionPopUp.CommandBar, 1);

                        command.AddControl(ReferencePopUp.CommandBar, 1);

                        command1.AddControl(ItemPopUp.CommandBar, 1);

                    }

                    catch (System.ArgumentException)

                    {

                    }

                }

            }

    public void QueryStatus(string commandName, vsCommandStatusTextWanted

              neededText, ref vsCommandStatus status, ref object commandText)

            {

                if (neededText ==

                  vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)

                {

                    if (commandName == "MyAddin9.Connect.ProjCmd")

                    {

                        status = (vsCommandStatus)vsCommandStatus.

                          vsCommandStatusSupported | vsCommandStatus.

                          vsCommandStatusEnabled;

                        return;

                    }

                    else if (commandName == "MyAddin9.Connect.SolutionCmd")

                    {

                        status = (vsCommandStatus)vsCommandStatus.

                          vsCommandStatusSupported | vsCommandStatus.

                          vsCommandStatusEnabled;

                        return;

                    }

                }

            }

    public void Exec(string commandName, vsCommandExecOption executeOption,

              ref object varIn, ref object varOut, ref bool handled)

            {

                handled = false;

                if (executeOption ==

                  vsCommandExecOption.vsCommandExecOptionDoDefault)

                {

                    if (commandName == "MyAddin9.Connect.ProjCmd")

                    {

                        handled = true;

                        return;

                    }

                    else if (commandName == "MyAddin9.Connect.SolutionCmd")

                    {

                        handled = true;

                        return;

                    }

                }

            }

    I didn’t find document about the controls enumeration, so please reference the picture:

    Hope this can help.

     

    Best Regards,

    Ziwei Chen

     

     

    • Proposed as answer by Victor_Chen Thursday, September 9, 2010 2:16 AM
    • Marked as answer by mark010101 Thursday, September 9, 2010 4:16 PM
    Thursday, September 9, 2010 2:16 AM
  • Thanks Victor.  My issue was that i was not 'drilling down' it seems.  I assumed _applcationObject.CommandBars["Project"] would retrieve the Project popup.  It seems to work in most of the cases except for Project.

    Ed, i believe to use that solution to identify which node is clicked, i would need the VS Extensibility SDK installed correct?  Thus far i have not had to do that and was hoping for a solution without it - but if it is the only way, then i may go that route.

    Thursday, September 9, 2010 4:19 PM
  • Hi Mark,

    You don't need the VS SDK, but it helps if you want to avoid (re)defining the interop interfaces, and make use of the ServiceProvider class to retrieve various services/interfaces, instead of calling IServiceProvider.QueryService (the COM version, not the .NET version), and then using the Marshal class to pull it out of an IntPrt. But that original article does just that, because I wanted to show that the technique didn't actually require the VS SDK.

    That all being said, you can certainly check to see what is currently selected in the Solution Explorer toolwindow via the stock automation services by way of the EnvDTE.UIHierarchy.SelectedItems method.

    I found an old post here, that details this: http://social.msdn.microsoft.com/Forums/en-US/vsx/thread/30c4c24d-4eb1-45a2-b6ea-a36ff52f119e/

    Sincerely,


    Ed Dore
    Friday, September 10, 2010 4:53 PM