Can you programmatically add a "Add-In" button to a context menu?

2498
8
12-15-2011 11:03 AM
KevinOrcutt
New Contributor
Howdy All,
     I have created an ArcGIS 10.0 Add-In, that when it is installed for the first time I would like to add the Button in it to the "featurelayer" context menu programmatically...  When I was developing it, the first time I ran it in debug mode I add to manually add the button to the feature layer context menu.  Is there a way that this can be done programmatically once and only once?  I have several hundred users that I would not like to have to explain to ALL of them how to do this step themselves the first time they install and run it...  

For that matter, I would also like to programmatically add it to a toolbar as well, but I figure, if I can figure out how to add to the context menu, the toolbar should be pretty similar...

I have added to the project an AddIns extension, that I have a couple lines of code in the OnStartup sub to set some variables up before the button/form is used for the first time.  I figure if need be, something could go in here to see if the button is in the context menu or not and add it if it is not already there...  Any thoughts???

Current Environment:
ArcMap 10.0 Service Pack 3, ArcInfo license level
ArcObjects SDK, Service Pack 1
Visual Studio 2010 Professional, Service Pack 1
VB.Net
Working on an ArcMap Add-In.

Thanks in advance,
Kevin Orcutt
0 Kudos
8 Replies
JeffreyHamblin
New Contributor III
I haven't implemented that before, but I suspect you will need to use ICommandBar, since its documentation mentions context menus.

I also think you're on the right track using an extension. You might want to have a look at this thread where we did something similar to add a menu to ArcMap's main menu bar:
Modify-(add)-to-MAIN-Toolbar-with-Addinx-files

Be sure to post back if you get anywhere -- or not.
0 Kudos
by Anonymous User
Not applicable
Yep, you can do it through an extension.

Here's the extension code where i add a button/command to an editor sketch context menu.
The commandUID.Value used here is the button ID of the add-in command you wish to add. Both the add-in extension and button are in the same VS solution. In your case you would use a regular arcmap add-in extension.
The only trick is finding the guid of the context menu...

using ESRI.ArcGIS.Editor;
using ESRI.ArcGIS.Framework;
using ESRI.ArcGIS.esriSystem;

namespace RestartSketch
{
  /// <summary>
  /// Editor Extension to add a context menu item
  /// </summary>
  public class RSExt : ESRI.ArcGIS.Desktop.AddIns.Extension
  {
    private IEditEvents_Event m_editEvents;

    public RSExt()
    {
    }

    protected override void OnStartup()
    {
      m_editEvents = ArcMap.Editor as IEditEvents_Event;
      m_editEvents.OnStartEditing += new IEditEvents_OnStartEditingEventHandler(m_editEvents_OnStartEditing);
     }

    void m_editEvents_OnStartEditing()
    {
      //Add to various sketch context menus by guid and bottom up position
      //AddtoContextMenu("{02D578D0-42AB-11d2-84D6-0000F875B9C6}", 3); //straight constructor context menu
      //AddtoContextMenu("{066022E8-A0FD-48e5-AF5D-F5C77E88DD42}", 3); //trace constructor
      //AddtoContextMenu("{68A337DF-751B-45dd-AA39-91194BE88D7C}", 3); //other constructors
      AddtoContextMenu("{FD799450-472C-11d2-84D8-0000F875B9C6}", 3); //over a sketch
    }

    private void AddtoContextMenu(string cmg, int pos)
    {
      // Get the context menu
      UID contextMenuUID = new UIDClass();
      contextMenuUID.Value = cmg;
      ICommandBar contextMenu = ArcMap.Application.Document.CommandBars.Find(contextMenuUID) as ICommandBar;

      if (contextMenu != null)
      {
        // Get the command item you want to add
        UID commandUID = new UIDClass();
        commandUID.Value = "ESRI_RestartSketch_RestartSketchCmd";
        
        //Check if it is already present on the context menu...
        ICommandItem myCmdItem = contextMenu.Find(commandUID);
        if (myCmdItem == null)
        {
          myCmdItem = contextMenu.Add(commandUID, contextMenu.Count - pos);
          //myCmdItem.Group = true;
          myCmdItem.Refresh();
        }
      }
    }
  }
}
0 Kudos
JeffreyHamblin
New Contributor III
I was also thinking, "The only trick is finding the guid of the context menu."

I found the following:

{BF643199-9062-11D2-AE71-080009EC732A}
esriArcMapUI.FeatureLayerContextMenu

in the 9.0 documentation for Names and IDs.

I couldn't find it in the similar 10.0 documentation. Maybe I'm looking in the wrong place?
0 Kudos
NeilClemmons
Regular Contributor III
Kevin, Sean's example is how you would do this sort of thing but I'd like to point out one major point.  Notice in his code how he is using the extension to register an event handler for the OnStartEditing event.  In this event, he checks to see if the command is already on the context menu and adds it if it is not.  The CommandBars collection is a property of the document, so the toolbars and menus can differ from one document to the next.  In your case you would want to listen for the NewDocument and OpenDocument events.  In these events you would check the context menu to see if the command needs to be added.
0 Kudos
JeffreyHamblin
New Contributor III
I threw something together, but it isn't working. Here is some C# test code for an Add-In extenstion attempting to add an item to the Feature Layer Context Menu:

protected override void OnStartup()
{
    WireEvents();
}

private void WireEvents()
{
    
    ArcMap.Events.OpenDocument +=
            new ESRI.ArcGIS.ArcMapUI.IDocumentEvents_OpenDocumentEventHandler(Events_OpenDocument);

    ArcMap.Events.NewDocument +=
            new ESRI.ArcGIS.ArcMapUI.IDocumentEvents_NewDocumentEventHandler(Events_NewDocument);
}

void Events_OpenDocument()
{
    System.Diagnostics.Debug.WriteLine("**** Events_OpenDocument ****");
    LoadContextMenu();
}

void Events_NewDocument()
{
    System.Diagnostics.Debug.WriteLine("**** Events_NewDocument ****");
    LoadContextMenu();
}

private void LoadContextMenu()
{
    ICommandBars cmdBars = ArcMap.Application.Document.CommandBars;

    UID contextMenuUID = new UIDClass();
    contextMenuUID.Value = "{BF643199-9062-11D2-AE71-080009EC732A}"; //esriArcMapUI.FeatureLayerContextMenu
    ICommandBar contextMenu = cmdBars.Find(contextMenuUID, false, true) as ICommandBar;

    if (contextMenu != null)
    {
        // Get the command item you want to add
        UID commandUID = new UIDClass();
        commandUID.Value = "Test_TestParaTextButton"; // Add-in button ID

        //Check if it is already present on the context menu.
        ICommandItem myCmdItem = contextMenu.Find(commandUID, false);

        if (myCmdItem == null)
        {
            Object pos = contextMenu.Count - 1;
            myCmdItem = contextMenu.Add(commandUID, ref pos);
            //myCmdItem.Group = true;
            myCmdItem.Refresh();
        }
    }
    else
    {
        System.Diagnostics.Debug.WriteLine("**** contextMenu is null ****");
    }

}


The contextMenu object is null on both calls to the method, so I suspect the GUID is either wrong or no longer supported.
0 Kudos
NeilClemmons
Regular Contributor III
I believe it's not finding it because you are setting the NoCreate parameter to True for the call to Find.  This means it won't create the object if it isn't already created.  Context menus are created on demand so there won't be an instance for Find to return unless it creates one.  Pass in False and your code should work.
0 Kudos
JeffreyHamblin
New Contributor III
Thanks, Neil! That makes it work. And thanks for the explanation.

Here is the corrected line that will fix the prior code:

ICommandBar contextMenu = cmdBars.Find(contextMenuUID, false, false) as ICommandBar;
0 Kudos
KevinOrcutt
New Contributor
Howdy All,
     First off, Thank you for all of the great responses...  Working through them all, I've come up with a pretty decent solution (It Works!!!)...  Code to follow...  Here is my class for the extension within the solution:

Imports ESRI.ArcGIS.ArcMapUI
Imports ESRI.ArcGIS.Framework

Public Class CycleThrough
    Inherits ESRI.ArcGIS.Desktop.AddIns.Extension

    Public Sub New()

    End Sub

    Protected Overrides Sub OnStartup()
        WireEvents()
    End Sub

    Protected Overrides Sub OnShutdown()

    End Sub

    Private Sub WireEvents()
        Dim docEvents As IDocumentEvents_Event
        Dim mapStatusEvents As IApplicationStatusEvents_Event

        docEvents = TryCast(My.ArcMap.Application.Document, IDocumentEvents_Event)
        AddHandler docEvents.NewDocument, AddressOf OnNewDocument
        AddHandler docEvents.OpenDocument, AddressOf OnOpenDocument
        If TypeOf My.ArcMap.Application.Document.Parent Is IMxApplication Then
            mapStatusEvents = TryCast(My.ArcMap.Application.Document.Parent, IApplicationStatusEvents_Event)
            AddHandler mapStatusEvents.Initialized, AddressOf OnInitialized
        End If
    End Sub

    Private Sub OnNewDocument()
        SetupContext()
    End Sub

    Private Sub OnOpenDocument()
        SetupContext()
    End Sub

    Private Sub OnInitialized()
        SetupContext()
    End Sub

    Private Sub SetupContext()
        Dim contextMenuGUID As New UID
        contextMenuGUID.Value = "{BF643199-9062-11D2-AE71-080009EC732A}"
        Dim myContextMenu As ICommandBar = My.ArcMap.Application.Document.CommandBars.Find(contextMenuGUID, False, False)

        If myContextMenu IsNot Nothing Then
            Dim commandGUID As New UID
            commandGUID.Value = "LayerCycle_CycleButton"
            Dim myCommandItem As ICommandItem = myContextMenu.Find(commandGUID)
            If myCommandItem Is Nothing Then
                myCommandItem = myContextMenu.Add(commandGUID, 9) 'the 9 is where I happen to want the button to be, it could be nothing or any other value 
                myCommandItem.Refresh()
            End If
        End If
    End Sub

End Class


Hey as a side note...  I too could NOT find the appropiate UID for the context menu in the 10.0 Docs...  I looked in the ArcObjects site:
ArcObjects SDK 10 Microsoft .Net Framework - ArcMap Commands

Hey Sean, you might want to mention to someone that that particular page might be missing some items that were in previous versions i.e. the 9.0 page, where Jeff was able to find it...

So once again, Thank you All for the responses!!!:cool: :cool: 


Kevin Orcutt
0 Kudos