从表单激活自定义ITool而不将其添加到ArcMap AddIn工具栏?


11

我正在开发ArcMap 10.0的外接程序,该外接程序将工具栏添加到ArcMap。OpenModelessDialogCommand该工具栏上的一个命令()按钮打开一个无模式的WinForms对话框,MyTool可以从中激活一个工具(),以便例如在地图上选择一个要素。

我的Config.esriaddinx包含以下命令和工具栏声明:

<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>

我遇到的问题是正在激活MyTool表单。我在网上发现的所有代码示例大致如下:

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

但是,这显然要求它MyTool实际出现在我的加载项的命令栏(例如工具栏)中。但是事实并非如此。所以,我接下来尝试了这个:

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

我什至考虑在AxToolbarControl表单中添加一个不可见的元素,并为此添加一个按钮MyTool。但是随后我遇到了如何将工具栏(通过SetBuddyControl)连接到打开的文档地图的问题。我不希望该工具单独运行AxMapControl,而是希望它直接与ArcMap中显示的主地图一起使用。

问题:
如何激活未添加到任何工具栏(或其他命令栏)的自定义工具?


如果您认为如果命令栏如广告所示那样,我的答案将对您有用,则可以在问题中添加“错误”标记。公开展示的脏衣服通常是厂商修复错误的良好动力。
Kirk Kuykendall

@Kirk,我打算这样做,但是我不能-我在这里没有足够的排名来创建新标签,而且bug似乎还不存在。请随时自行编辑标签。
stakx 2011年

Answers:


7

使用ArcGIS 10 SP1对我有用。我的自定义工具不在工具栏上:

    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

1
+1如果可行,这个确定比我发布的答案要简单。我敢肯定我尝试过,但是自从安装了SP1,所以也许这是一个因素。
Kirk Kuykendall

lbross的回答对我很有帮助。后来,我在ArcGis片段查找器中找到了几乎相同的解决方案:“声明-在Windows Form.snippet中使用工具”(我正在使用C#)由于我的声誉太低,我无法投票赞成答案。
dpalmetz 2013年

我没有足够的声誉,所以我无法投票或添加评论,但是lbross的答案对我而言在ArcGIS 10.2中有效。我创建了一个itool用于不带工具栏,并把它称为从Windows按钮维克托
vaparicio

3

我从未尝试过,但似乎应该可以使用:在您的无模式形式中,有两个成员变量,第一个(m_Tool)引用您的ITool,第二个(m_Application)引用IApplication。在无模式形式的构造函数中,让它实例化ITool并调用OnCreate,并传递IApplication引用。

在无模式表单上有一个按钮,单击该按钮将设置m_Application。CurrentTool = m_Tool。另外,建议不要使用无停靠对话框,而建议使用可停靠窗口,或者在其中使用WPF

更新 为了弥补这一la脚的答案,我尝试过一起破解。看来您应该能够动态创建工具栏,将其隐藏,向其中添加工具(将ICommandItem设置为CurrentTool),然后在用户不知道该工具在工具栏上的情况下删除该工具栏。但是,ICommandBar.Dock和ICommandItem.Delete似乎不适用于动态工具栏。恕我直言,这是一个错误。

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(); 
    }
}

1
这将不起作用,因为CurrentTool属性需要ICommandItem。ICommandItem引用不能直接创建,而只能通过ICommandBars检索。
Petr Krebs

关于currenttool相当正确,但是ICommandbar.Add从UID创建ICommandItem。然后,问题就变成了在不再需要(或至少将其隐藏)后如何摆脱命令栏。
Kirk Kuykendall

哇,感谢您在更新中添加了有效的代码示例。遗憾的是,这既Dock没有Delete工作也没有工作,但这是一个好的开始。我Delete认为,我将进一步研究这个问题。
stakx 2011年

多么有趣的想法,我一定会尽力加以阐述。顺便说一句,我也相信您描述的行为是一个错误。
彼得·克雷布斯

我最终使用了一个不同的解决方案(除其他外,通过将我的工具设置为Singleton,以便我可以轻松地获得它的引用;由于CommandBars.Find某种未知的原因,问题突然解决了),但我给出了这个答案标记,因为这可能是我会做的。
stakx 2011年

3

我不知道为什么需要在工具栏中添加该工具。因为,我已经处理过一些类似的事情,所以没有发现需要在工具栏中添加任何内容。

就我而言,当用户单击可停靠窗口中的按钮时,就会激活一个工具。为了执行此工作,我的工具类如下所示:

  • 我的工具ID是:“ ArcMap_SelectionTool”
  • 我的工具类名称是:“ SelectionTool”
  • 在工具类中保留工具类型的静态字段

    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
    }

因此,无论何时需要实例化此工具,我都可以通过以下方式调用它:

        var toolInstance = SelectionTool.Instance;

使用该工具后,我需要退出工具实例。所以我叫SelectionTool.ExitToolInstance()方法。

此过程对我来说很好。


1

我通常通过将命令(在您的情况下为OpenModelessDialogCommand)也用作工具(ITool)来解决此问题。单击命令后,我打开表格。然后,我也可以随时将其激活为工具。

如果您要激活的工具不是您自己的,则可以将来自ITool(如上实现)的调用中继到另一个工具实例。


0

如果您有权访问地图对象,则可以通过调用onCreate来运行许多工具,例如发送MapControl对象以将其连接到地图。之后,仅运行onClick方法。

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

不要使用所有ESRI工具,因为有些工具需要添加到工具栏中。


我如何获得对此类地图对象的引用?我似乎只能得到IMap通过的接口IMxDocument,但是显然不一样,是吗?
stakx 2011年

编辑:在桌面它是挂钩对象的IApplication:help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/...
MathiasWestin

对不起,我尝试了这个;它不起作用。这里的问题是该工具已创建,但从未激活。其次,我仍然看不到如何获得MapControl对象(如果我真的需要一个IApplication对象)或从那里可以到达的任何对象。
stakx 2011年

如果我没有误读文档,则应在I Desktop中将IApplication传递给OnCreate。在Engine中,发送MapControl对象对我有用。
MathiasWestin

IApplication对象传递给OnCreate- 似乎是正确的,但这还不够(至少不是我的自定义工具),因为该工具没有被激活OnCreate,因此不会收到任何输入事件。
stakx 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.