Активировать пользовательский ITool из формы, не добавляя его на панель инструментов ArcMap AddIn?

11

Я работаю над надстройкой для ArcMap 10.0, которая добавляет панель инструментов в ArcMap. Одна OpenModelessDialogCommandкнопка command ( ) на этой панели инструментов открывает немодальное диалоговое окно WinForms, из которого MyToolможно активировать инструмент ( ), например, для выбора объекта на карте.

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

Вопрос:
Как активировать пользовательский инструмент, который не добавляется ни на одну панель инструментов (или в другую панель команд, в этом отношении)?

stakx
источник
Если вы думаете, что мой ответ сработает для вас, если панель команд работает так, как рекламируется, возможно, добавьте тег «ошибка» к вашему вопросу. Грязное белье, показанное на публике, часто является хорошей мотивацией для продавца исправить ошибку.
Кирк Куйкендалл
@Kirk, я собирался это сделать, но не могу - у меня недостаточно места для создания новых тегов, и bug, похоже, его пока нет; пожалуйста, не стесняйтесь редактировать теги самостоятельно.
Stakx

Ответы:

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
lbross
источник
1
+1 Если это работает, это, конечно, проще, чем ответ, который я опубликовал. Я уверен, что попробовал это, но с тех пор установил SP1, так что, возможно, это было фактором.
Кирк Куйкендалл
Ответ lbross мне очень помог. Позже я нашел почти такое же решение в искателе фрагментов ArcGis: «Выражения - используйте инструмент в Windows Form.snippet» (я использую C #). Я не могу проголосовать за ответ, потому что у меня слишком мало репутации.
dpalmetz
Я не могу голосовать или добавлять комментарии, потому что у меня недостаточно репутации, но ответ lbross мне подходит в ArcGIS 10.2. Я создал ITool без панели инструментов и вызвал его с помощью кнопки Windows Víctor
vaparicio
3

Я никогда не пробовал этого, но, похоже, он должен работать: в вашей немодальной форме есть две переменные-члены: первая (m_Tool) ссылается на ваш ITool, а вторая (m_Application) ссылается на IApplication. В конструкторе для вашей немодальной формы сделайте так, чтобы он создал экземпляр ITool и вызвал OnCreate , передав ссылку на приложение IApplication.

На вашей немодальной форме есть кнопка, которая при нажатии устанавливает m_Application. CurrentTool = m_Tool. Кроме того, вместо использования немодального диалога, я бы рекомендовал использовать закрепляемое окно, возможно, используя в нем WPF .

Обновление В попытке искоренить публикацию этого неубедительного ответа я попытался что-то взломать вместе. Похоже, вы должны иметь возможность динамически создавать панель инструментов, скрывать ее, добавлять к ней инструмент (получая 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.
Петр Кребс
Совершенно верно для currenttool, но ICommandbar.Add создает ICommandItem из UID. Тогда возникает проблема, как избавиться от командной строки после того, как она больше не нужна (или, по крайней мере, скрыть ее).
Кирк Куйкендалл
вау, спасибо за добавление примера рабочего кода в ваше обновление. Это позор , что ни Dockни Deleteработа, но это начало хорошее. Думаю, я займусь этим Deleteвопросом дальше.
Stakx
какая интересная идея, я определенно постараюсь уточнить из этого. Кстати, я также считаю, что поведение, которое вы описываете, является ошибкой.
Петр Кребс
Я закончил тем, что использовал другое решение (помимо прочего, сделав свой инструмент синглтоном, чтобы я мог легко получить ссылку на него; CommandBars.Findпроблема внезапно решилась сама по какой-то неизвестной причине), но я даю этот ответ галочкой Марк, потому что это, вероятно, то, что я бы сделал.
Stakx
3

Я не знаю, почему вам нужно добавить инструмент на панели инструментов. Потому что я работал с чем-то похожим, и мне не нужно добавлять его в панель инструментов.

В моем случае, когда пользователь нажимает кнопку в присоединяемом окне, инструмент активируется. Для выполнения этой работы мой класс инструментов выглядит следующим образом:

  • Мой идентификатор инструмента: "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()метод.

Эта процедура отлично работает для меня.

Emi
источник
1

Обычно я решаю эту проблему, делая команду (OpenModelessDialogCommand в вашем случае) также инструментом ( ITool). Нажав на команду, я открываю форму. Тогда я также могу активировать его как инструмент в любой момент.

Если инструмент, который вы хотите активировать, не является вашим собственным, вы можете переадресовывать вызовы с вашего ITool (реализовано, как описано выше) на другой экземпляр инструмента.

Петр Кребс
источник
0

Если у вас есть доступ к объекту карты, многие инструменты можно запустить, вызвав onCreate, отправив, например, объект MapControl, чтобы подключить его к карте. После этого нужно только запустить метод onClick.

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

Не работайте со всеми инструментами ESRI, потому что некоторые из них необходимо добавить на панель инструментов.

MathiasWestin
источник
Как бы я получить ссылку на такой объект карты? Все, что я могу когда-либо получить, это IMapчерез интерфейс IMxDocument, но ясно, что это не то же самое, не так ли?
stakx
Изменить: в Desktop это IApplication, который является объектом ловушки: help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/…
MathiasWestin
извини, я попробовал это; это не работает Проблема в том, что инструмент создается, но никогда не активируется. Во-вторых, я до сих пор не понимаю, как я могу получить MapControlобъект (если он мне вообще нужен) IApplicationили любой объект, до которого можно добраться.
Stakx
Вы должны передать IApplication в OnCreate при выполнении этого в Desktop, если я не читаю документацию. Отправка в объекте MapControl у меня работает в Engine.
MathiasWestin
кажется правильным, что вы передадите IApplicationобъект OnCreate- но этого недостаточно (по крайней мере, не для моего пользовательского инструмента), потому что инструмент не активируется OnCreateи, следовательно, не будет получать никаких входных событий.
Stakx