[GIS] ArcObjects (ArcGIS for Desktop and C#): How to cast between the ArcMap COM UI and the custom .Net UserControl objects

arcmaparcobjectsceventsnet

I'm creating a utility to run in ArcGIS for Desktop using ArcObjects (9.3.1 SDK) and C#.Net. My prototype involves a toolbar with two comboboxes and a tool. The first combo selects a layer in the TOC, and the second selects a field from the selected layer. The tool will be used to interact with the map.

Basically I want to select a layer, select a valid field, then click a feature in the map and get its value for the chosen field. Here's an image of the toolbar, if it helps:

enter image description here

[question almost entirely re-worded from here down]

The problem I am having is passing state between the native COM UI parts and my custom .Net controls. For example, I want to catch the DropDownClosed event on the Layer combobox, assemble a valid list of columns relative to that layer, then apply the list of field names (via IFields) to the Fields combobox.

After applying some the initial comments by RagiYaserBurham and blah238, and merging them with details from this page, the following DropDownClosed event handler does go from the combobox back to the toolbar (ICommandBar), but I don't understand how to cast from ICommandItem back to my implementation of the Fields combobox in a 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);

}

So.. now that I'm here.. how do I cast fieldsItem to FieldSelectUC ?

[The Solution]

As blah238 suggested, I tried casting ICommandItem.Command to my custom UserControl implementation and that did the trick.

First, I had to add a public accessor to my FieldSelectUC UserControl to return a reference to its ComboBox; that simple accessor looks like this:

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

With that modification in place, here's a DropDownClosed event handler that will populate the Fields combobox with all the fields of the selected layer:

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!");
    }
}

This is still a dirty testbed (hence AngryToolbar). But the solution shows how to start from an extended UserControl that implements ICommand and IToolControl and drill back down to a .Net component. I really appreciate the assistance of everyone who offered suggestions. Thanks so much. 🙂

Best Answer

As I understand it, you have two .NET ComboBoxes on a UserControl that implements ICommand and IToolControl, and you want to get a reference to one of the combo boxes from the other. As long as they are in the same scope you should just be able to refer to them by their variable names (check your UserControl designer for the names of your controls).

If the two combo boxes are on separate UserControls, then try casting ICommandItem.Command to your other UserControl.

See this sample in the 9.3 help for some examples: Recently used files - Command, MultiItem, and ToolControl

Also here is an ESRI forum post discussing this issue: http://forums.esri.com/Thread.asp?c=93&f=993&t=170088

Related Question