Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

I'm working on an add-in for ArcMap 10.0 that adds a toolbar to ArcMap. One command (OpenModelessDialogCommand) button on that toolbar opens a modeless WinForms dialog, from which a tool (MyTool) can be activated in order to e.g. select a feature on the map.

My Config.esriaddinx contains these command and toolbar declarations:

<Commands>
  <!-- this is the command that opens the modeless WinForms form, from where
       MyTool is available: -->
  <Button id="OpenModelessFormCommand" ... />
  <!-- MyTool is not directly referenced in any toolbar defined in this file: -->
  <Tool id="MyTool" class="MyTool" ... />
</Commands>
<Toolbars>
  <Toolbar ...>
    <Items>
      <Button refID="OpenModelessFormCommand" />
    </Items>
  </Toolbar>
</Toolbars>

What I'm having problems with is activating MyTool in the form. All I've found on the internet is code samples along the lines of:

// get a reference to an instance of MyTool:
ICommandItem myTool = ArcMap.Application.Document.CommandBars.Find("MyTool");
 // activate MyTool: 
ArcMap.Application.CurrentTool = myTool;

However, this apparently requires that MyTool actually appears in a command bar (e.g. toolbar) of my add-in. But that's not the case. So, I've tried this next:

ITool myTool = new MyTool();
ArcMap.Application.CurrentTool = myTool;  // Type mismatch! An ICommandItem is expected.

I've even looked into adding an invisible AxToolbarControl to my form and adding a button for MyTool there; but then I'm running into problems on how to connect that toolbar (via SetBuddyControl) to the opened document's map. I don't want the tool to function in a separate AxMapControl, I want it to work directly with the main map shown in ArcMap.

Question:
How do I activate a custom tool that is not added to any toolbar (or other command bar, for that matter)?

share|improve this question
    
If you think my answer would work for you if commandbar worked as advertised, perhaps add a "bug" tag to your question. Dirty laundry shown in public is often good motivation for a vendor to fix a bug. –  Kirk Kuykendall Mar 14 '11 at 16:15
    
@Kirk, I was going to do that, but I can't -- I haven't got enough rank here to create new tags, and bug doesn't seem to exist yet; please feel free to edit the tags yourself. –  stakx Mar 21 '11 at 17:25

6 Answers 6

up vote 2 down vote accepted

I've never tried this, but seems like it should work: In your modeless form have two member variables, the first (m_Tool) referencing your ITool and the second (m_Application) referencing the IApplication. In the constructor for your modeless form, have it instantiate the ITool and call OnCreate, passing an IApplication reference.

On your modeless form have a button that, when clicked sets m_Application.CurrentTool = m_Tool. Also, instead of doing a modeless dialog, I'd recommend using a dockable window perhaps using using WPF within it.

Update In an attempt to atone for posting this lame answer, I've tried to hack something together. It seems like you should be able to dynamically create a toolbar, hide it, add the tool to it (getting an ICommandItem to set to CurrentTool), then delete the toolbar without the user ever knowing the tool was on a toolbar. However, ICommandBar.Dock and ICommandItem.Delete don't seem to work for dynamic toobars. IMHO this is a bug.

protected override void OnClick()
{
    UID uid = new UIDClass();
    uid.Value = "Microsoft_ArcMapAddin1_Tool1";
    var bar = ArcMap.Application.Document.CommandBars.Create("mybar", esriCmdBarType.esriCmdBarTypeToolbar)
        as ICommandBar;

    // bug, dock doesn't work ...
    bar.Dock(esriDockFlags.esriDockHide);
    bar.Add(uid);

    var itm = bar.Find(uid);
    if (itm != null)
    {
        ArcMap.Application.CurrentTool = itm;
        // bug, delete doesn't work either
        ((ICommandItem)bar).Delete(); 
    }
}
share|improve this answer
1  
This will not work, since CurrentTool property expects an ICommandItem. ICommandItem references cannot be created directly, but can only be retrieved through ICommandBars. –  Petr Krebs Mar 11 '11 at 16:15
    
Quite right about currenttool, but ICommandbar.Add creates an ICommandItem from a UID. Problem then becomes how to get rid of the commandbar after it is no longer needed (or at least hiding it). –  Kirk Kuykendall Mar 11 '11 at 21:05
    
wow, thanks for adding a working code example in your update. It's a shame that neither Dock nor Delete work, but it's a good start. I'll look into the Delete issue further, I think. –  stakx Mar 11 '11 at 22:24
    
what an interesting idea, I'll definitely try to elaborate from that. Btw I also believe the behavior you describe is a bug. –  Petr Krebs Mar 12 '11 at 1:40
    
I ended up using a different solution (among other things, by making my tool a Singleton so that I can easily get a reference to it; the CommandBars.Find problem suddenly solved itself, for some unknown reason), but I'm giving this answer the tick mark because this is probably what I would have done. –  stakx Mar 21 '11 at 17:23

This worked for me using ArcGIS 10 SP1. My custom tool is not on a toolbar:

    Dim UIDCls As ESRI.ArcGIS.esriSystem.UID = New ESRI.ArcGIS.esriSystem.UIDClass()
    ' id property of menu from Config.esriaddinx document
    UIDCls.Value = "ClassLibraryAddin_MyTool"
    Dim document As ESRI.ArcGIS.Framework.IDocument = My.ArcMap.Document
    Dim commandItem As ESRI.ArcGIS.Framework.ICommandItem = TryCast(document.CommandBars.Find(UIDCls), ESRI.ArcGIS.Framework.ICommandItem)
    If commandItem Is Nothing Then
        Exit Sub
    End If
    My.ArcMap.Application.CurrentTool = commandItem
share|improve this answer
    
+1 If this works, this sure is simpler than the answer I posted. I'm pretty sure I tried that but have since installed SP1, so maybe that was a factor. –  Kirk Kuykendall Apr 14 '11 at 3:02
    
Worked great for me, thanks for sharing the code. –  Rich Wawrzonek Oct 6 '12 at 0:47
    
I cannot vote or add comments because I don´t have enough reputation, but lbross´s answer works for me in ArcGIS 10.2. I created a ITool without a toolbar and called it from a Windows button Víctor –  vaparicio May 9 at 7:35

I usually solve this by making the command (OpenModelessDialogCommand in your case) also a tool (ITool). Upon clicking the command, I open up the form. Then I can also activate it as a tool at any moment.

If the tool you want to activate is not your own, you can relay calls from your ITool (implemented as above) to the other tool instance.

share|improve this answer

The answer of lbross helped me a lot. Later I found almost the same solution in the ArcGis snippet finder: 'Statements - Use a Tool in a Windows Form.snippet' (I am using C#)

I can't vote the answer up because I have too less reputation.

share|improve this answer

If you have access to the map object, many tools can be runned by making a call to onCreate sending in for example the MapControl object to hook it up to the map. After that it's only to run the onClick method.

tool.OnCreate(control.Object)
tool.OnClick()

Don't work on all ESRI tools because some need to added to a toolbar.

share|improve this answer
    
How would I get a reference to such a map object? All I can ever seem to get is an IMap interface through IMxDocument, but clearly that's not the same, is it? –  stakx Mar 11 '11 at 17:00
    
Edit: in Desktop it's the IApplication that is the hook object: help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/… –  MathiasWestin Mar 11 '11 at 21:28
    
sorry, I tried this; it doesn't work. The problem here is that the tool gets created, but is never activated. Second, I still don't see how I could get a MapControl object (if I actually need one at all) through IApplication or any object reachable from there. –  stakx Mar 11 '11 at 23:38
    
You should pass in IApplication to OnCreate when doing this in Desktop, if I'm not misreading the documentation. Sending in a MapControl object works for me in Engine. –  MathiasWestin Mar 12 '11 at 8:04
    
it seems correct that you would pass an IApplication object to OnCreate -- but that does not suffice (at least not for my custom tool), because the tool does not get activated by OnCreate, and will therefore not receive any input events. –  stakx Mar 12 '11 at 11:44

I don't know why do you need to add the tool in a toolbar. Because, I have worked with some similar thing and I haven't find any need to add it in the tool bar.

In my case, when user clicks on a button in the dockable window, a tool activates. To perform this work, my tool class looks like following:

  • My tool id is:"ArcMap_SelectionTool"
  • My tool class name is: "SelectionTool"
  • Keep a static field of tool type in the tool class

    private static ICommandItem _selectionTool;
    private static SelectionTool _instance;
    public static SelectionTool Instance
    {
        get
        {
            if (_instance == null)
            {
                var selectionToolUID = new UID();
                selectionToolUID.Value = "ArcMap_SelectionTool";
                _selectionTool = ArcMap.Application.Document.CommandBars.Find(selectionToolUID, false, false);
                if (_selectionTool == null)
                {
                    MessageBox.Show("Selection tool is not found.");
                    return null;
                }
            }
            if (_selectionTool != null)
                ArcMap.Application.CurrentTool = _selectionTool;
            return _instance;
        }
    }
    
    public static void ExitToolInstance()
    {
        if (_instance != null)
            ArcMap.Application.CurrentTool = null;
    }
    
    public SelectionTool()
    {
        _instance = this;
    }
    
    protected override void OnMouseDown(MouseEventArgs arg)
    {
        if (arg.Button != MouseButtons.Left)
            return;
        //Do Work
    }
    

So, whenever I need to instantiate this tool, I call it in the following way:

        var toolInstance = SelectionTool.Instance;

After working with the tool, I need to exit tool instance. So I call SelectionTool.ExitToolInstance() method.

This procedure works fine for me.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.