ArcObjects (ArcGIS for Desktop e C #): come eseguire il cast tra linterfaccia utente di ArcMap COM e gli oggetti .Net UserControl personalizzati?

Sto creando unutilità da eseguire in ArcGIS for Desktop utilizzando ArcObjects (9.3.1 SDK) e C # .Net. Il mio prototipo prevede una barra degli strumenti con due caselle combinate e uno strumento. La prima combinazione seleziona un livello nel sommario e la seconda seleziona un campo dal livello selezionato. Lo strumento verrà utilizzato per interagire con la mappa.

Fondamentalmente voglio selezionare un layer, seleziona un campo valido, quindi fai clic su un elemento nella mappa e ottieni il suo valore per il campo scelto. Ecco unimmagine della barra degli strumenti, se aiuta:

inserisci qui la descrizione dellimmagine

[domanda quasi interamente riformulata da qui in basso]

Il problema che sto riscontrando è il passaggio di stato tra le parti dellinterfaccia utente COM nativa ei miei controlli .Net personalizzati. Ad esempio, voglio catturare levento DropDownClosed nella casella combinata Layer, assemblare un elenco valido di colonne relative a quel layer, quindi applicare lelenco dei nomi di campo (tramite IFields) alla casella combinata Fields.

Dopo applicando alcuni dei commenti iniziali di RagiYaserBurham e blah238, e unendoli ai dettagli di questa pagina , il seguente gestore di eventi DropDownClosed torna dalla casella combinata alla barra degli strumenti ( ICommandBar), ma non capisco come trasmettere da ICommandItem alla mia implementazione della casella combinata Fields in un UserControl:

private void layerSelectCBO_DropDownClosed(object sender, EventArgs e) { _completionNotify.SetComplete(); string layerName = (sender as ComboBox).SelectedItem as string; // These two lines are a combination of initial commenter suggestions. ICommandItem toolbar = _iApp.Document.CommandBars.Find("ArcProject.UI.AngryToolbar", false, false); ICommandItem fieldsItem = (toolbar as ICommandBar).Find("ArcProject.UI.FieldSelectUC", false); } 

Quindi … ora che Sono qui .. come faccio a trasmettere fieldItem a FieldSelectUC?

[ La soluzione ]

Come suggerito da blah238, ho provato a trasmettere ICommandItem.Command alla mia implementazione UserControl personalizzata e questo ha funzionato.

Innanzitutto, ho dovuto aggiungere una funzione di accesso pubblico al mio FieldSelectUC UserControl per restituire un riferimento al suo ComboBox; quella semplice funzione di accesso è simile a questa:

// fieldSelectCBO is the name of the combobox control in the design view.. public ComboBox FieldsComboBox { get { return fieldSelectCBO; } } 

Con quella modifica in atto, ecco “un gestore di eventi DropDownClosed che popolerà la casella combinata Fields con tutti i campi del livello selezionato:

private void layerSelectCBO_DropDownClosed(object sender, EventArgs e) { _completionNotify.SetComplete(); string layerName = (sender as ComboBox).SelectedItem as string; // get the toolbar.. ICommandItem toolbar = _iApp.Document.CommandBars.Find("ArcProject.UI.AngryToolbar", false, false); // get my fields combo by way of CommandItem.Command.. ICommandItem fieldsCI = (toolbar as ICommandBar).Find("ArcProject.UI.FieldSelectUC", false); FieldSelectUC fieldsUC = fieldsCI.Command as FieldSelectUC; ComboBox fieldsComboBox = fieldsUC.FieldsComboBox; // get the fields for the selected layer.. IFields fields = null; int layerCount = _iDoc.FocusMap.LayerCount; int i; for (i = 0; i < layerCount; i++) { if (_iDoc.FocusMap.get_Layer(i).Name == layerName) { if (_iDoc.FocusMap.get_Layer(i) is FeatureLayer) { fields = (_iDoc.FocusMap.get_Layer(i) as FeatureLayer).FeatureClass.Fields; } } } // Build a list of field names for the combobox items.. List<string> fieldNameList = new List<string>(); if (fields != null) { int fieldCount = fields.FieldCount; int j; for (j = 0; j < fieldCount; j++) { string oneFieldName = fields.get_Field(j).Name; fieldNameList.Add(oneFieldName); } } // Populate the combobox items.. if (fieldNameList.Count > 0) { fieldsComboBox.Items.Clear(); foreach (string fieldName in fieldNameList) { fieldsComboBox.Items.Add(fieldName); } fieldsComboBox.SelectedItem = fieldsComboBox.Items[0]; } else { fieldsComboBox.Items.Add("Error: No fields!"); } } 

Questo è ancora un banco di prova sporco (da qui AngryToolbar). Ma la soluzione mostra come iniziare da un UserControl esteso che implementa ICommand e IToolControl e visualizzare in dettaglio un componente .Net. Apprezzo molto lassistenza di tutti coloro che hanno offerto suggerimenti. Grazie mille. 🙂

Commenti

  • Come su come rendere lambito statico pubblico variabile di layerName?
  • @ artwork21, suona bene, ma ‘ non sono ancora sicuro di come accedere allistanza di una delle caselle combinate da la sua controparte sulla barra degli strumenti? Sai cosa intendo? Sospetto che ‘ sia una semplice cosa fondamentale di cui ‘ non sono a conoscenza.
  • Questo suona come un diff domanda erent. ‘ non è chiaro perché è necessario farlo. Mi sembra che la casella combinata Fields debba essere cancellata e ripopolata in base alla combinazione Layer. La casella combinata Layer dovrebbe essere popolata in base al listener di eventi del documento.
  • @RichWawrzonek che è esattamente giusto. Ma ‘ non sono sicuro di come raggiungere listanza esistente della combinazione Fields dalla combinazione Layers. Per questo motivo, lo strumento deve leggere entrambi i valori.

Answer

A quanto ho capito, hai due .NET ComboBox su un UserControl che implementa ICommand e IToolControl e si desidera ottenere un riferimento a una delle caselle combinate dallaltra. Finché sono nello stesso ambito, dovresti essere in grado di fare riferimento a loro tramite i loro nomi di variabile (controlla il tuo designer UserControl per i nomi dei tuoi controlli).

Se le due caselle combinate sono separate UserControls, quindi prova a trasmettere ICommandItem.Command allaltro tuo UserControl.

Vedi questo esempio nella guida 9.3 per alcuni esempi: File utilizzati di recente: Command, MultiItem e ToolControl

Anche qui cè un post sul forum ESRI che discute di questo problema: http://forums.esri.com/Thread.asp?c=93&f=993&t=170088

Commenti

  • Bingo. Questa riga ha fatto il trucco per tornare dallistanza di ICommandItem alla UserControl classe che ho implementato: FieldSelectUC fs = fieldsItem.Command as FieldSelectUC; Ora posso vedere tutti i ‘ oggetti di scena nel debugger. Grazie mille a te.
  • Evviva! ‘ uso esclusivamente i componenti aggiuntivi da un po di tempo, quindi ho dovuto esaminare alcune vecchie cose per ricordare come funzionava 🙂 Questo genere di cose è molto più semplice (anche se bisogna ammetterlo meno flessibile) con componenti aggiuntivi in 10 poiché esiste un tipo ComboBox specifico e puoi semplicemente fare riferimento ad altri componenti aggiuntivi con variabili e metodi statici.
  • Sì, sembrava decisamente più facile grazie ai nuovi componenti aggiuntivi. Durante la ricerca ho trovato componenti aggiuntivi questo e altri, ma semplicemente ‘ t disponibili per la mia implementazione. Lesempio GraphicsLayerToolControl nella guida di .Net (sul mio sistema lindirizzo è C:\Program Files (x86)\ArcGIS\DeveloperKit\SamplesNET\Desktop\GraphicsLayerToolControl\CSharp\GraphicsLayerToolControl2008.sln) che mi ha aiutato ad andare avanti con UserControl ed eventi, ma non potevo ‘ t capire come perforare un foro attraverso .Net dal controllo COM. Non posso ‘ esagerare per quanto sono grato. Cordiali saluti.

Risposta

Ogni volta che faccio questo genere di cose, memorizzo i nomi dei livelli e dei campi in un file statico insieme di proprietà contenuto nella barra degli strumenti. Quindi utilizzo un gestore di eventi del documento per verificare se i livelli vengono aggiunti / rimossi da ArcMap o se il documento è stato modificato. Le proprietà del livello e del campo vengono aggiornate ogni volta che vengono modificate nel menu a discesa dallutente. Se il layer viene rimosso da ArcMap o il documento viene chiuso, vengono reimpostati su null. Quindi puoi semplicemente controllare i valori nulli prima che il tuo programma venga eseguito.

Ottieni un riferimento alla casella combinata tramite linterfaccia ICommandItem:

ICommandItem toolbar = _iApp.Document.CommandBars.Find (“ArcProject.UI.AngryToolbar”, false, false);
ICommandItem fieldsItem = (barra degli strumenti come ICommandBar) .Find (“ArcProject.UI.FieldSelectUC”, false); IComboBox cbo = (IComboBox) fieldsItem; // Richiede un riferimento a ESRI.ArcGIS.SystemUI;

Commenti

  • +1 lo fai sembrare così facile. 🙂 Ma il problema che ho è accedere alle proprietà di un controllo già istanziato dal punto di vista di qualsiasi altro controllo. Mi piace la tua idea di mettere le loro proprietà condivise sulla barra degli strumenti, potresti aggiornare la tua risposta per mostrare come posso effettivamente leggere le proprietà della barra degli strumenti contenitore dal punto di vista di una delle caselle combinate? ‘ Perché ‘ è fondamentalmente quello che ‘ m dopo. So già come utilizzare gli eventi del documento per ascoltare le modifiche al sommario, quindi ‘ non ho bisogno di aiuto con questo aspetto. Grazie per la tua risposta.
  • @elrobis Puoi anche mettere lo stato condiviso nello stesso ICommand (dato che ci sarà sempre una sola istanza) e poi fare in modo che i controlli ottengano un handle per il comando tramite help.arcgis.com/en/sdk/10.0/arcobjects_net/componenthelp/…
  • Ragi è giusto. Dato che stai usando la barra degli strumenti COM puoi semplicemente passare luid della tua casella combinata al metodo ICommandBar.Find per ottenere un riferimento. Il suo link spiega tutto.
  • Mi piace anche lidea di Ragi ‘. Cè qualcosa di fondamentale che mi manca, però. Ad esempio, questa riga restituisce una barra degli strumenti nulla (dove this è un UserControl con etichetta e casella combinata): ICommandBar toolbar = this.Parent as ICommandBar; È ‘ questo tipo di attraversamento fondamentale degli oggetti dellinterfaccia utente che mi sta uccidendo. Non ‘ non so come tornare alla barra degli strumenti per implementare uno dei tuoi suggerimenti. (E in realtà mi piace un po meglio lidea di queste variabili sulla barra degli strumenti. ‘ probabilmente lo farei aggiungendo un getter pubblico alla barra degli strumenti che applica Ragi ‘ s idea). Grazie per il vostro continuo aiuto.
  • Non ‘ credo che this.Parent sia valido per le interfacce COM, ovvero un concetto .NET / Windows Forms. Non ‘ vuoi ” attraversare linterfaccia utente “, vuoi accedere al tuo ICommandi in base al loro ID.

Risposta

Ho avuto un problema simile con uno strumento personalizzato. Ho un modulo personalizzato che viene aperto da un pulsante su una barra degli strumenti AddIn in ArcGis 10.x. In questo modulo è presente un pulsante che dovrebbe recuperare le coordinate di un clic nella mappa, compreso lo snap. Potevo avviare lo strumento e gestire il clic nella mappa, ma non riuscivo a riportare il valore al mio modulo, perché il cast allo strumento personalizzato falliva sempre. La soluzione era utilizzare AddIn da ESRI.ArcGIS.Desktop.AddIns. Con questo è stato facile accedere a ogni proprietà e metodo del mio strumento personalizzato. La documentazione dellESRI risiede qui: http://resources.arcgis.com/en/help/arcobjects-net/conceptualhelp/index.html#/Add_in_coding_patterns/0001000000zz000000/

Ecco lo snippet di codice da OnClick- Evento del pulsante nel modulo personalizzato:

//DESCRIPTION: //Connect a tool embedded in a Windows Form with the ArcGIS Application Framework. ESRI.ArcGIS.esriSystem.IUID UIDCls = new ESRI.ArcGIS.esriSystem.UIDClass(); UIDCls.Value = "MyNamespace_MyCustomTool"; IDocument actDoc = (IDocument)ArcMap.Document; //Finding the customTool ESRI.ArcGIS.Framework.ICommandItem commandItem = actDoc.CommandBars.Find(UIDCls, false, false); if (commandItem == null) { return; } //This cast would fail: //MyCustomTool_Class actCustomTool2 = (MyCustomTool_Class)commandItem.Command; MyCustomTool_Class actCustomTool = AddIn.FromID<MyCustomTool_Class (ThisAddIn.IDs.MyCustomTool); actCustomTool.actFrm = this; ArcMap.Application.CurrentTool = commandItem; 

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *