Activer ITool personnalisé à partir du formulaire sans l'ajouter à la barre d'outils ArcMap AddIn?

11

Je travaille sur un complément pour ArcMap 10.0 qui ajoute une barre d'outils à ArcMap. Un OpenModelessDialogCommandbouton de commande ( ) de cette barre d'outils ouvre une boîte de dialogue WinForms non modale, à partir de laquelle un outil ( MyTool) peut être activé afin par exemple de sélectionner une entité sur la carte.

My Config.esriaddinxcontient ces déclarations de commandes et de barres d'outils:

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

Ce qui me pose problème, c'est l'activation MyTooldans le formulaire. Tout ce que j'ai trouvé sur Internet, ce sont des exemples de code du type:

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

Cependant, cela nécessite apparemment que MyTools'affiche réellement dans une barre de commandes (par exemple la barre d'outils) de mon complément. Mais ce n'est pas le cas. J'ai donc essayé ceci ensuite:

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

J'ai même cherché à ajouter un invisible AxToolbarControlà mon formulaire et à y ajouter un bouton MyTool; mais je rencontre des problèmes sur la façon de connecter cette barre d'outils (via SetBuddyControl) à la carte du document ouvert. Je ne veux pas que l'outil fonctionne dans un environnement distinct AxMapControl, je veux qu'il fonctionne directement avec la carte principale affichée dans ArcMap.

Question:
Comment puis-je activer un outil personnalisé qui n'est ajouté à aucune barre d'outils (ou à une autre barre de commandes, d'ailleurs)?

stakx
la source
Si vous pensez que ma réponse fonctionnerait pour vous si la barre de commandes fonctionnait comme annoncé, ajoutez peut-être une balise "bug" à votre question. Le linge sale montré en public est souvent une bonne motivation pour un vendeur de corriger un bug.
Kirk Kuykendall
@Kirk, j'allais le faire, mais je ne peux pas - je n'ai pas assez de rang ici pour créer de nouveaux tags, et bugne semble pas encore exister; n'hésitez pas à modifier les balises vous-même.
stakx

Réponses:

7

Cela a fonctionné pour moi en utilisant ArcGIS 10 SP1. Mon outil personnalisé n'est pas sur une barre d'outils:

    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
la source
1
+1 Si cela fonctionne, c'est bien plus simple que la réponse que j'ai postée. Je suis presque sûr d'avoir essayé, mais j'ai depuis installé le SP1, alors peut-être que c'était un facteur.
Kirk Kuykendall
La réponse de lbross m'a beaucoup aidé. Plus tard, j'ai trouvé presque la même solution dans l'outil de recherche d'extraits d'ArcGis: `` Déclarations - Utiliser un outil dans un Windows Form.snippet '' (j'utilise C #) Je ne peux pas voter pour la réponse car j'ai trop moins de réputation.
dpalmetz
Je ne peux pas voter ou ajouter de commentaires car je n'ai pas assez de réputation, mais la réponse de lbross fonctionne pour moi dans ArcGIS 10.2. J'ai créé un ITool sans barre d'outils et l'ai appelé à partir d'un bouton Windows Víctor
vaparicio
3

Je n'ai jamais essayé cela, mais il semble que cela devrait fonctionner: dans votre formulaire non modal, deux variables membres, la première (m_Tool) référençant votre ITool et la seconde (m_Application) référençant l'IApplication. Dans le constructeur de votre formulaire non modal, faites-le instancier ITool et appelez OnCreate , en passant une référence IApplication.

Sur votre formulaire non modal, vous avez un bouton qui, lorsque vous cliquez dessus, définit m_Application. CurrentTool = m_Tool. De plus, au lieu de faire une boîte de dialogue non modale, je recommanderais d'utiliser une fenêtre ancrable, peut-être en utilisant WPF .

Mise à jour Dans une tentative d'expier pour publier cette réponse boiteuse, j'ai essayé de pirater quelque chose ensemble. Il semble que vous devriez pouvoir créer dynamiquement une barre d'outils, la cacher, y ajouter l'outil (obtenir un ICommandItem à définir sur CurrentTool), puis supprimer la barre d'outils sans que l'utilisateur sache que l'outil était sur une barre d'outils. Cependant, ICommandBar.Dock et ICommandItem.Delete ne semblent pas fonctionner pour les barres d'outils dynamiques. À mon humble avis, c'est un 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
la source
1
Cela ne fonctionnera pas, car la propriété CurrentTool attend un ICommandItem. Les références ICommandItem ne peuvent pas être créées directement, mais peuvent uniquement être récupérées via ICommandBars.
Petr Krebs
Tout à fait à propos de currenttool, mais ICommandbar.Add crée un ICommandItem à partir d'un UID. Le problème devient alors comment se débarrasser de la barre de commandes après qu'elle ne soit plus nécessaire (ou du moins la cacher).
Kirk Kuykendall
wow, merci d'avoir ajouté un exemple de code de travail dans votre mise à jour. Il est dommage que ni Dockni Deletetravail, mais il est un bon début. Je vais approfondir la Deletequestion, je pense.
stakx
quelle idée intéressante, je vais certainement essayer de développer à partir de cela. Btw Je crois aussi que le comportement que vous décrivez est un bug.
Petr Krebs
J'ai fini par utiliser une solution différente (entre autres choses, en faisant de mon outil un singleton afin que je puisse facilement y avoir une référence; le CommandBars.Findproblème s'est soudainement résolu, pour une raison inconnue), mais je coche cette réponse marque parce que c'est probablement ce que j'aurais fait.
stakx
3

Je ne sais pas pourquoi avez-vous besoin d'ajouter l'outil dans une barre d'outils. Parce que j'ai travaillé avec quelque chose de similaire et je n'ai trouvé aucun besoin de l'ajouter dans la barre d'outils.

Dans mon cas, lorsque l'utilisateur clique sur un bouton de la fenêtre ancrable, un outil s'active. Pour effectuer ce travail, ma classe d'outils ressemble à ceci:

  • L'ID de mon outil est: "ArcMap_SelectionTool"
  • Le nom de ma classe d'outils est: "SelectionTool"
  • Conserver un champ statique de type d'outil dans la classe d'outils

    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
    }

Donc, chaque fois que j'ai besoin d'instancier cet outil, je l'appelle de la manière suivante:

        var toolInstance = SelectionTool.Instance;

Après avoir travaillé avec l'outil, je dois quitter l'instance d'outil. J'appelle donc SelectionTool.ExitToolInstance()méthode.

Cette procédure fonctionne bien pour moi.

Emi
la source
1

Je résous généralement ce problème en faisant de la commande (OpenModelessDialogCommand dans votre cas) également un outil ( ITool). En cliquant sur la commande, j'ouvre le formulaire. Ensuite, je peux également l'activer en tant qu'outil à tout moment.

Si l'outil que vous souhaitez activer n'est pas le vôtre, vous pouvez relayer les appels de votre ITool (implémenté comme ci-dessus) vers l'autre instance d'outil.

Petr Krebs
la source
0

Si vous avez accès à l'objet carte, de nombreux outils peuvent être exécutés en appelant onCreate en envoyant par exemple l'objet MapControl pour le connecter à la carte. Après cela, il suffit d'exécuter la méthode onClick.

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

Ne fonctionne pas sur tous les outils ESRI car certains doivent être ajoutés à une barre d'outils.

MathiasWestin
la source
Comment puis-je obtenir une référence à un tel objet de carte? Tout ce que je peux obtenir, c'est une IMapinterface IMxDocument, mais ce n'est clairement pas la même chose, n'est-ce pas?
stakx
Edit: dans Desktop, c'est l'IApplication qui est l'objet hook: help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/…
MathiasWestin
désolé, j'ai essayé ceci; ça ne marche pas. Le problème ici est que l'outil est créé, mais n'est jamais activé. Deuxièmement, je ne vois toujours pas comment je pourrais faire passer un MapControlobjet (si j'en ai réellement besoin) IApplicationou tout objet accessible à partir de là.
stakx
Vous devez transmettre IApplication à OnCreate lorsque vous effectuez cette opération sur le bureau, si je ne lis pas mal la documentation. L'envoi d'un objet MapControl fonctionne pour moi dans Engine.
MathiasWestin
il semble correct que vous passiez un IApplicationobjet à OnCreate- mais cela ne suffit pas (du moins pas pour mon outil personnalisé), car l'outil n'est pas activé par OnCreate, et ne recevra donc aucun événement d'entrée.
stakx