Ativando o ITool personalizado a partir do formulário sem adicioná-lo à barra de ferramentas do ArcMap AddIn?

11

Estou trabalhando em um suplemento para o ArcMap 10.0 que adiciona uma barra de ferramentas ao ArcMap. Um OpenModelessDialogCommandbotão de comando ( ) nessa barra de ferramentas abre uma caixa de diálogo WinForms sem modelagem, na qual uma ferramenta ( MyTool) pode ser ativada para, por exemplo, selecionar um recurso no mapa.

My Config.esriaddinxcontém estas declarações de comando e barra de ferramentas:

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

Estou tendo problemas com a ativação MyTooldo formulário. Tudo o que eu encontrei na internet são exemplos de código ao longo das linhas de:

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

No entanto, isso aparentemente requer que MyToolrealmente apareça em uma barra de comandos (por exemplo, barra de ferramentas) do meu suplemento. Mas esse não é o caso. Então, eu tentei isso a seguir:

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

Eu até tentei adicionar um invisível AxToolbarControlao meu formulário e adicionar um botão por MyToollá; mas estou com problemas para conectar a barra de ferramentas (via SetBuddyControl) ao mapa do documento aberto. Não quero que a ferramenta funcione separadamente AxMapControl, quero que ela funcione diretamente com o mapa principal mostrado no ArcMap.

Pergunta:
Como ativo uma ferramenta personalizada que não é adicionada a nenhuma barra de ferramentas (ou outra barra de comandos)?

stakx
fonte
Se você acha que minha resposta funcionaria para você se a barra de comando funcionasse como anunciado, talvez adicione uma tag "bug" à sua pergunta. A roupa suja mostrada em público geralmente é uma boa motivação para um fornecedor corrigir um bug.
Kirk Kuykendall
@ Kirk, eu ia fazer isso, mas não posso - não tenho classificação suficiente aqui para criar novas tags e bugparece que ainda não existe; sinta-se à vontade para editar as tags.
stakx

Respostas:

7

Isso funcionou para mim usando o ArcGIS 10 SP1. Minha ferramenta personalizada não está em uma barra de ferramentas:

    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
fonte
1
+1 Se isso funcionar, isso com certeza é mais simples do que a resposta que eu postei. Tenho certeza de que tentei isso, mas já instalei o SP1, então talvez isso tenha sido um fator.
precisa saber é o seguinte
A resposta da lbross me ajudou muito. Mais tarde, encontrei quase a mesma solução no localizador de snippets do ArcGis: 'Declarações - Use uma ferramenta no Windows Form.snippet' (estou usando C #) Não posso votar na resposta porque tenho muito menos reputação.
Dpalmetz
Não posso votar ou adicionar comentários porque não tenho reputação suficiente, mas a resposta da lbross funciona para mim no ArcGIS 10.2. Eu criei um iTool sem uma barra de ferramentas e chamou-lhe a partir de um botão do Windows Víctor
vaparicio
3

Eu nunca tentei isso, mas parece que deveria funcionar: No seu formulário sem modelo, existem duas variáveis ​​de membro, a primeira (m_Tool) referenciando seu ITool e a segunda (m_Application) referenciando o IApplication. No construtor para seu formulário sem modelo, instancie o ITool e chame OnCreate , passando uma referência de IApplication.

No formulário sem modelo, há um botão que, quando clicado, define m_Application. CurrentTool = m_Tool. Além disso, em vez de fazer uma caixa de diálogo sem modelo, eu recomendaria o uso de uma janela acoplável, talvez usando o WPF dentro dela .

Atualização Na tentativa de reparar a publicação desta resposta esfarrapada, tentei hackear algo juntos. Parece que você deve ser capaz de criar dinamicamente uma barra de ferramentas, ocultá-la, adicionar a ferramenta a ela (fazer com que um ICommandItem seja definido como CurrentTool) e excluir a barra de ferramentas sem que o usuário saiba que a ferramenta estava em uma barra de ferramentas. No entanto, ICommandBar.Dock e ICommandItem.Delete não parecem funcionar para barras de controle dinâmicas. IMHO isso é um 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(); 
    }
}
Kirk Kuykendall
fonte
1
Isso não funcionará, pois a propriedade CurrentTool espera um ICommandItem. As referências ICommandItem não podem ser criadas diretamente, mas somente podem ser recuperadas através de ICommandBars.
Petr Krebs
Muito bem sobre a ferramenta atual, mas o ICommandbar.Add cria um ICommandItem a partir de um UID. O problema passa a ser como se livrar da barra de comandos depois que ela não é mais necessária (ou pelo menos a oculta).
21411 Kirk Kuykendall
uau, obrigado por adicionar um exemplo de código funcional na sua atualização. É uma pena que Docknem Deletefuncione, mas é um bom começo. Pensarei mais sobre o Deleteassunto.
stakx
que idéia interessante, definitivamente tentarei elaborar a partir disso. Btw também acredito que o comportamento que você descreve é ​​um bug.
Petr Krebs
Acabei usando uma solução diferente (entre outras coisas, tornando minha ferramenta um Singleton para que eu possa facilmente fazer uma referência a ela; o CommandBars.Findproblema de repente se resolveu, por algum motivo desconhecido), mas estou dando essa resposta marcar, porque isso é provavelmente o que eu teria feito.
stakx
3

Não sei por que você precisa adicionar a ferramenta em uma barra de ferramentas. Porque, trabalhei com algo semelhante e não encontrei necessidade de adicioná-lo na barra de ferramentas.

No meu caso, quando o usuário clica em um botão na janela acoplável, uma ferramenta é ativada. Para executar este trabalho, minha classe de ferramentas se parece com a seguinte:

  • O ID da minha ferramenta é: "ArcMap_SelectionTool"
  • O nome da minha classe de ferramenta é: "SelectionTool"
  • Mantenha um campo estático do tipo de ferramenta na classe de ferramentas

    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
    }

Portanto, sempre que preciso instanciar essa ferramenta, eu a chamo da seguinte maneira:

        var toolInstance = SelectionTool.Instance;

Depois de trabalhar com a ferramenta, preciso sair da instância da ferramenta. Então eu chamo SelectionTool.ExitToolInstance()método.

Este procedimento funciona bem para mim.

Emi
fonte
1

Geralmente resolvo isso fazendo o comando (OpenModelessDialogCommand no seu caso) também uma ferramenta ( ITool). Ao clicar no comando, abro o formulário. Então eu também posso ativá-lo como uma ferramenta a qualquer momento.

Se a ferramenta que você deseja ativar não for sua, você poderá retransmitir chamadas do seu ITool (implementado como acima) para a outra instância da ferramenta.

Petr Krebs
fonte
0

Se você tiver acesso ao objeto de mapa, muitas ferramentas poderão ser executadas fazendo uma chamada para o onCreate enviando, por exemplo, o objeto MapControl para conectá-lo ao mapa. Depois disso, é apenas para executar o método onClick.

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

Não trabalhe em todas as ferramentas ESRI, porque algumas precisam ser adicionadas a uma barra de ferramentas.

MathiasWestin
fonte
Como obter uma referência a esse objeto de mapa? Tudo o que consigo entender é uma IMapinterface IMxDocument, mas claramente isso não é o mesmo, é?
stakx
Edit: no Desktop é o IApplication que é o objeto de gancho: help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/…
MathiasWestin
desculpe, eu tentei isso; isso não funciona. O problema aqui é que a ferramenta é criada, mas nunca é ativada. Segundo, ainda não vejo como conseguir um MapControlobjeto (se realmente precisar de um) IApplicationou qualquer outro objeto acessível a partir daí.
stakx
Você deve passar o IApplication para o OnCreate ao fazer isso no Desktop, se não estiver interpretando mal a documentação. Enviar em um objeto MapControl funciona para mim no Engine.
MathiasWestin
parece correto que você passaria um IApplicationobjeto para OnCreate- mas isso não é suficiente (pelo menos não para a minha ferramenta personalizada), porque a ferramenta não é ativada OnCreatee, portanto, não recebe nenhum evento de entrada.
stakx