Estou criando um utilitário para executar no ArcGIS for Desktop usando ArcObjects (9.3.1 SDK) e C # .Net. Meu protótipo envolve uma barra de ferramentas com dois caixas de combinação e uma ferramenta. A primeira combinação seleciona uma camada no sumário e a segunda seleciona um campo da camada selecionada. A ferramenta será usada para interagir com o mapa.
Basicamente, eu quero selecionar um camada, selecione um campo válido e, em seguida, clique em um elemento no mapa e obtenha seu valor para o campo escolhido. Aqui está uma imagem da barra de ferramentas, se ajudar:
[pergunta quase totalmente reformulada daqui para baixo]
O problema que estou tendo é a passagem de estado entre as partes nativas da interface do usuário COM e meus controles .Net personalizados. Por exemplo, quero capturar o evento DropDownClosed na caixa de combinação Camada, montar uma lista válida de colunas relativas a essa camada e, em seguida, aplicar a lista de nomes de campo (via IFields) à caixa de combinação Campos.
Depois aplicando alguns dos comentários iniciais de RagiYaserBurham e blah238, e mesclando-os com os detalhes desta página , o manipulador de eventos DropDownClosed a seguir vai da combobox de volta para a barra de ferramentas ( ICommandBar), mas eu não entendo como converter ICommandItem de volta para minha implementação da caixa de combinação Fields em um 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); }
Então … agora que Estou aqui .. como faço para lançar fieldsItem em FieldSelectUC?
[ A solução ]
Como blah238 sugeriu, tentei lançar ICommandItem.Command para minha implementação UserControl personalizada e isso funcionou.
Primeiro, eu tive que adicionar um acessador público ao meu FieldSelectUC
UserControl para retornar uma referência ao seu ComboBox; aquele acessador simples se parece com isto:
// fieldSelectCBO is the name of the combobox control in the design view.. public ComboBox FieldsComboBox { get { return fieldSelectCBO; } }
Com essa modificação em vigor, aqui “um manipulador de eventos DropDownClosed que preencherá a caixa de combinação Fields com todos os campos do camada selecionada:
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!"); } }
Este ainda é um testbed sujo (portanto, AngryToolbar). Mas a solução mostra como iniciar a partir de um UserControl estendido que implementa ICommand e IToolControl e volte para um componente .Net. Agradeço muito a ajuda de todos que ofereceram sugestões. Muito obrigado. 🙂
Comentários
- Como sobre como tornar o escopo estático público da variável layerName?
- @ artwork21, parece bom, mas eu ‘ m ainda não tenho certeza de como acessar a instância de qualquer uma das caixas de combinação sua contraparte na barra de ferramentas? Sabe o que quero dizer? Suspeito que seja ‘ uma coisa simples e fundamental da qual ‘ não estou ciente.
- Isso soa como uma diferença pergunta anterior. Eu ‘ não estou claro por que você precisa fazer isso. Parece-me que a caixa de combinação Fields deve ser limpa e preenchida novamente com base na combinação de camadas. A caixa de combinação da camada deve ser preenchida com base no ouvinte de evento do documento.
- @RichWawrzonek isso é exatamente correto. Mas eu ‘ não tenho certeza de como chegar à instância existente do combo Fields a partir do combo Layers. Para esse assunto, a ferramenta precisa ler os dois valores.
Resposta
Pelo que entendi, você tem dois .NET ComboBoxes em um UserControl que implementa ICommand e IToolControl, e você deseja obter uma referência para uma das caixas de combinação da outra. Contanto que eles estejam no mesmo escopo, você deve apenas ser capaz de se referir a eles por seus nomes de variáveis (verifique seu designer de UserControl para os nomes de seus controles).
Se as duas caixas de combinação estiverem separadas UserControls e, em seguida, tente transmitir ICommandItem.Command
para seu outro UserControl.
Veja este exemplo na ajuda 9.3 para obter alguns exemplos: Arquivos usados recentemente – Comando, MultiItem e ToolControl
Também aqui está uma postagem do fórum da ESRI discutindo esse problema: http://forums.esri.com/Thread.asp?c=93&f=993&t=170088
Comentários
- Bingo. Esta linha funcionou para passar da instância de
ICommandItem
de volta para aUserControl
classe que implementei:FieldSelectUC fs = fieldsItem.Command as FieldSelectUC;
Agora posso ver todos os ‘ s adereços no depurador. Muito obrigado a você. - Viva! Eu ‘ uso suplementos exclusivamente há um tempo, então tive que vasculhar algumas coisas antigas para lembrar como tudo funcionava 🙂 Esse tipo de coisa é muito mais fácil (embora reconheço menos flexível) com suplementos em 10, pois há um tipo específico de ComboBox e você pode apenas referir-se a outros componentes de suplemento com variáveis e métodos estáticos.
- Sim, definitivamente parecia mais fácil com os novos suplementos. Ao pesquisar isso, encontrei suplementos para isto e outros adicionais, mas eles simplesmente não estavam ‘ disponíveis para minha implementação. O exemplo GraphicsLayerToolControl na ajuda .Net (em meu sistema, esse endereço é
C:\Program Files (x86)\ArcGIS\DeveloperKit\SamplesNET\Desktop\GraphicsLayerToolControl\CSharp\GraphicsLayerToolControl2008.sln
) que me ajudou a prosseguir com o UserControl e as coisas de eventos, mas não consegui ‘ t descobrir como fazer um furo no .Net a partir do controle COM. Não posso ‘ exagerar o quanto estou grato. Atenciosamente.
Resposta
Sempre que faço esse tipo de coisa, armazeno os nomes da camada e dos campos em um formato estático conjunto de propriedades contido na barra de ferramentas. Então eu uso um manipulador de eventos de documento para verificar se as camadas são adicionadas / removidas do ArcMap ou se o documento é alterado. As propriedades da camada e do campo são atualizadas sempre que são alteradas no menu suspenso pelo usuário. Se a camada for removida do ArcMap ou o documento for fechado, eles serão redefinidos como nulos. Em seguida, você pode apenas verificar os valores nulos antes da execução do programa.
Obtenha uma referência para a combobox através da interface ICommandItem:
ICommandItem toolbar = _iApp.Document.CommandBars.Find (“ArcProject.UI.AngryToolbar”, false, false);
ICommandItem fieldsItem = (barra de ferramentas como ICommandBar) .Find (“ArcProject.UI.FieldSelectUC”, false); IComboBox cbo = (IComboBox) fieldsItem; // Precisa de uma referência para ESRI.ArcGIS.SystemUI;
Comentários
- +1 você faz parecer tão fácil. 🙂 Mas o problema que tenho é acessar as propriedades de um controle já instanciado do ponto de vista de qualquer outro controle. Eu gosto da sua ideia de colocar suas propriedades compartilhadas na barra de ferramentas. Você poderia atualizar sua resposta para mostrar como eu posso realmente ler as propriedades da barra de ferramentas do ponto de vista de uma das caixas de combinação? ‘ Porque ‘ é basicamente o que eu ‘ m depois. Já sei como usar eventos de documento para escutar mudanças no sumário, então não ‘ não preciso de ajuda com esse aspecto. Obrigado pela sua resposta.
- @elrobis Você também pode colocar o estado compartilhado no próprio ICommand (uma vez que sempre haverá apenas uma instância) e então fazer com que os controles obtenham um identificador para o comando por meio de help.arcgis.com/en/sdk/10.0/arcobjects_net/componenthelp/…
- Ragi é direita. Já que você está usando a barra de ferramentas COM, você pode simplesmente passar o uid de sua combobox para o método ICommandBar.Find para obter uma referência. Seu link explica tudo.
- Também gosto da ideia de Ragi ‘. Porém, há algo fundamental que estou perdendo. Por exemplo, esta linha retorna uma barra de ferramentas nula (onde
this
é umUserControl
com rótulo e combobox):ICommandBar toolbar = this.Parent as ICommandBar;
É ‘ esse tipo de passagem de objeto de IU fundamental que está me matando. Não ‘ não sei como voltar à barra de ferramentas para implementar qualquer uma de suas sugestões. (E, na verdade, gosto um pouco mais da ideia desses vars na barra de ferramentas. Eu ‘ d provavelmente faço isso adicionando um getter público à barra de ferramentas que aplica Ragi ‘ s ideia). Obrigado por sua ajuda contínua. - Eu não ‘ acho que
this.Parent
é válido para interfaces COM – isto é um conceito .NET / Windows Forms. Você não ‘ t deseja ” atravessar a IU “, deseja acessar seu IComandos por seus IDs.
Resposta
Tive um problema semelhante com uma ferramenta personalizada. Eu tenho um formulário personalizado que é aberto por um botão em um AddIn-Toolbar no ArcGis 10.x. Neste formulário existe um botão que deve recuperar as coordenadas de um clique no mapa, incluindo o snap. Eu poderia iniciar a ferramenta e manipular o clique no mapa, mas não consegui obter o valor de volta para o meu formulário, porque a conversão para a ferramenta personalizada sempre falhava. A solução foi usar AddIn de ESRI.ArcGIS.Desktop.AddIns. Com isso, foi fácil obter acesso a todas as propriedades e métodos de minha ferramenta personalizada. A documentação dos ESRIs reside aqui: http://resources.arcgis.com/en/help/arcobjects-net/conceptualhelp/index.html#/Add_in_coding_patterns/0001000000zz000000/
Aqui está o snippet de código do OnClick- Evento do botão no formulário personalizado:
//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;