Tworzę narzędzie do uruchamiania w ArcGIS for Desktop przy użyciu ArcObjects (9.3.1 SDK) i C # .Net. Mój prototyp obejmuje pasek narzędzi z dwoma combo i narzędzie. Pierwsza kombinacja wybiera warstwę w spisie treści, a druga wybiera pole z wybranej warstwy. Narzędzie będzie używane do interakcji z mapą.
Zasadniczo chcę wybrać wybierz prawidłowe pole, a następnie kliknij obiekt na mapie i uzyskaj jego wartość dla wybranego pola. Oto obraz paska narzędzi, jeśli to pomoże:
[pytanie prawie całkowicie zmienione od tego miejsca]
Problem, który mam, polega na przekazywaniu stanu między natywnymi częściami interfejsu użytkownika interfejsu COM a moimi niestandardowymi kontrolkami .Net. Na przykład chcę przechwycić zdarzenie DropDownClosed w polu Combo Layer, zebrać prawidłową listę kolumn względem tej warstwy, a następnie zastosować listę nazw pól (za pośrednictwem IFields) do pola ComboBox Pola.
Po stosując niektóre początkowe komentarze RagiYaserBurham i blah238 i łącząc je ze szczegółami z tej strony , następująca procedura obsługi zdarzenia DropDownClosed przechodzi z pola combo z powrotem do paska narzędzi ( ICommandBar), ale nie rozumiem, jak rzutować z ICommandItem z powrotem do mojej implementacji pola combobox Fields w 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); }
Więc … teraz to Jestem tutaj … jak rzutować fieldItem na FieldSelectUC?
[ Rozwiązanie ]
Jak zasugerował blah238, próbowałem rzutować ICommandItem.Command na moją niestandardową implementację UserControl i to załatwiło sprawę.
Najpierw musiałem dodać publiczny dostęp do mojego FieldSelectUC
UserControl, aby zwrócić odwołanie do jego ComboBox; ten prosty akcesor wygląda następująco:
// fieldSelectCBO is the name of the combobox control in the design view.. public ComboBox FieldsComboBox { get { return fieldSelectCBO; } }
Po wprowadzeniu tej modyfikacji, oto moduł obsługi zdarzenia DropDownClosed, który zapełni pole kombinowane Fields wszystkimi polami z wybrana warstwa:
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!"); } }
To wciąż brudne stanowisko testowe (stąd AngryToolbar). Ale rozwiązanie pokazuje, jak zacząć od rozszerzonej UserControl, która implementuje ICommand i IToolControl oraz przejdź z powrotem do komponentu .Net. Naprawdę doceniam pomoc każdego, kto przedstawił sugestie. Bardzo dziękuję. 🙂
Komentarze
- Jak o ustawieniu zmiennej LayerName w publicznym zasięgu statycznym?
- @ artwork21, to brzmi dobrze, ale ja ' nadal nie wiem, jak uzyskać dostęp do instancji któregoś z kombinacji combobox z jego odpowiednik na pasku narzędzi? Wiesz, co mam na myśli? Podejrzewam, że ' to prosta podstawowa rzecz, której ' po prostu nie jestem świadomy.
- To brzmi jak różnica jedno pytanie. ' nie wiem, dlaczego musisz to zrobić. Wydaje mi się, że kombinacja Fields powinna zostać wyczyszczona i ponownie zapełniona w oparciu o kombinację warstw. Pole combo Layer powinno być wypełnione na podstawie detektora zdarzeń dokumentu.
- @RichWawrzonek, dokładnie tak. Ale ' nie jestem pewien, jak dostać się do istniejącej instancji kombi Fields z kombinacji Layers. W tym przypadku narzędzie musi odczytać obie ich wartości.
Odpowiedź
Jak rozumiem, masz dwa ComboBoxes .NET na kontrolerze UserControl, który implementuje ICommand i IToolControl, oraz chcesz uzyskać odniesienie do jednego z pól kombi z drugiego. Dopóki są w tym samym zakresie, powinieneś mieć możliwość odwoływania się do nich poprzez nazwy zmiennych (sprawdź nazwy kontrolek w swoim projektancie UserControl).
Jeśli oba pola kombi są na osobnych UserControls, a następnie spróbuj przesłać ICommandItem.Command
do innej UserControl.
Zobacz ten przykład w pomocy 9.3, aby zapoznać się z przykładami: Ostatnio używane pliki – Command, MultiItem i ToolControl
Również tutaj jest post na forum ESRI omawiający ten problem: http://forums.esri.com/Thread.asp?c=93&f=993&t=170088
Komentarze
- Bingo. Ta linia wystarczyła, aby dostać się z instancji
ICommandItem
z powrotem doUserControl
klasy, którą zaimplementowałem:FieldSelectUC fs = fieldsItem.Command as FieldSelectUC;
Teraz widzę wszystko to ' w debugerze. Ogromne dzięki Tobie. - Hurra! ' od jakiegoś czasu używam dodatków na wyłączność, więc musiałem przekopać się przez kilka starych rzeczy, aby przypomnieć sobie, jak to wszystko działało 🙂 Takie rzeczy są znacznie łatwiejsze (choć trzeba przyznać mniej elastyczny) z dodatkami w 10, ponieważ istnieje określony typ ComboBox i możesz po prostu odwołać się do innych składników dodatku za pomocą zmiennych statycznych i metod.
- Tak, z pewnością wydawało się to łatwiejsze dzięki nowym dodatkom. Badając to, znalazłem dodatki to i tamto, ale po prostu nie były ' niedostępne dla mojej implementacji. Przykład GraphicsLayerToolControl w pomocy .Net (w moim systemie ten adres to
C:\Program Files (x86)\ArcGIS\DeveloperKit\SamplesNET\Desktop\GraphicsLayerToolControl\CSharp\GraphicsLayerToolControl2008.sln
), który pomógł mi przejść do obsługi UserControl i zdarzeń, ale po prostu nie mogłem ' nie wymyślić, jak przebić dziurę do .Net z kontrolki COM. Nie mogę ' wyolbrzymiać, jak bardzo jestem wdzięczny. Z poważaniem.
Odpowiedź
Za każdym razem, gdy robię takie rzeczy, przechowuję nazwy warstw i pól w postaci statycznej zestaw właściwości zawarty na pasku narzędzi. Następnie używam modułu obsługi zdarzeń dokumentu, aby sprawdzić, czy warstwy są dodane / usunięte z ArcMap lub czy dokument został zmieniony. Właściwości warstwy i pola są aktualizowane po każdej zmianie w menu rozwijanym przez użytkownika. Jeśli warstwa zostanie usunięta z ArcMap lub dokument zostanie zamknięty, zostaną zresetowane do wartości null. Następnie możesz po prostu sprawdzić wartości null przed uruchomieniem programu.
Uzyskaj odwołanie do combobox za pośrednictwem interfejsu ICommandItem:
ICommandItem toolbar = _iApp.Document.CommandBars.Find („ArcProject.UI.AngryToolbar”, false, false);
ICommandItem fieldsItem = (pasek narzędzi jako ICommandBar) .Find („ArcProject.UI.FieldSelectUC”, false); IComboBox cbo = (IComboBox) fieldsItem; // Potrzebuje odniesienia do ESRI.ArcGIS.SystemUI;
Komentarze
- +1, dzięki czemu brzmi to tak prosto. 🙂 Ale problem, jaki mam, polega na dostępie do właściwości kontrolki, której instancja została już utworzona, z punktu widzenia dowolnej innej kontrolki. Podoba mi się twój pomysł umieszczenia ich wspólnych właściwości na pasku narzędzi. Czy mógłbyś zaktualizować swoją odpowiedź, aby pokazać, w jaki sposób mogę faktycznie odczytać właściwości zawierającego pasek narzędzi z punktu widzenia jednego z comboboxów? ' Ponieważ ' jest w zasadzie tym, co ' m później. Wiem już, jak używać zdarzeń dokumentu do nasłuchiwania zmian w spisie treści, więc nie ' nie potrzebuję pomocy w tym aspekcie. Dziękuję za odpowiedź.
- @elrobis Możesz także umieścić stan współdzielenia w samym ICommand (ponieważ zawsze będzie tylko jedna instancja), a następnie kontrolki otrzymają uchwyt do polecenia poprzez help.arcgis.com/en/sdk/10.0/arcobjects_net/componenthelp/…
- Ragi jest dobrze. Ponieważ używasz paska narzędzi COM, możesz po prostu przekazać uid swojego combobox do metody ICommandBar.Find, aby uzyskać referencję. Jego link wyjaśnia wszystko.
- Podoba mi się też pomysł Ragiego '. Jednak brakuje mi czegoś fundamentalnego. Na przykład ta linia zwraca pusty pasek narzędzi (gdzie
this
toUserControl
z etykietą i combobox):ICommandBar toolbar = this.Parent as ICommandBar;
To ' jest tego rodzaju podstawowym przechodzeniem przez obiekt interfejsu użytkownika, który mnie zabija. Nie ' nie wiem, jak wrócić do paska narzędzi, aby zastosować którąkolwiek z twoich sugestii. (I właściwie bardziej podoba mi się pomysł tych zmiennych na pasku narzędzi. ' d prawdopodobnie robię to, dodając publiczny getter do paska narzędzi, który stosuje Ragi '). Dziękuję za dalszą pomoc. - Nie ' nie sądzę, że
this.Parent
jest poprawne dla interfejsów COM – to znaczy koncepcja .NET / Windows Forms. Nie ' nie chcesz ” przechodzić przez interfejs użytkownika „, chcesz uzyskać dostęp do ICommands według ich identyfikatorów.
Odpowiedź
Miałem podobny problem z niestandardowym narzędziem. Mam niestandardowy formularz, który jest otwierany za pomocą przycisku na pasku narzędzi dodatków w ArcGis 10.x. Na tym formularzu znajduje się przycisk, który powinien oddawać współrzędne kliknięcia na mapie, włączając przyciąganie. Mogłem uruchomić narzędzie i obsłużyć kliknięcie na mapie, ale nie mogłem przywrócić wartości do mojego formularza, ponieważ rzutowanie na narzędzie niestandardowe zawsze kończyło się niepowodzeniem. Rozwiązaniem było użycie AddIn z ESRI.ArcGIS.Desktop.AddIns. Dzięki temu łatwo było uzyskać dostęp do każdej właściwości i metody mojego niestandardowego narzędzia. Dokumentacja ESRI znajduje się tutaj: http://resources.arcgis.com/en/help/arcobjects-net/conceptualhelp/index.html#/Add_in_coding_patterns/0001000000zz000000/
Oto fragment kodu z OnClick- Zdarzenie przycisku w formularzu niestandardowym:
//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;