0

I'm starting developing with ArcObjects and I'm stuck at trying to make two comboboxes talk to each other. What am I trying to do is changing the contents/selection of ComboBox B based on the selection of ComboBox A. But so far I don't know how to get the ComboBox B instantiation inside ComboBox A code.

An example code I found so far use ICommandBars, but it needs an IApplication reference that ComboBoxes do not receive as parameter in their initialize() method. Another example is by using method findExtensionByCLSID(UID), but it also needs an IApplication reference.

Can someone give me a hint on how to grab another add-in component informations (such as selected item in ComboBoxes)?

A piece of code I have to try catching a ComboBox instantiation is presented below (this code is inside a combo named DimCombo, and tries to pick a FormaCombo combo instance to do some work). I guess my problem is at setting the app variable, as it is not given in combos initialization method.

public void getFormaCombo(){
    try{
        UID pUID = new UID();
        pUID.setValue("br.mil.eb.dsg.arctools.formacombo");
        formaCombo = (FormaCombo) app.findExtensionByCLSID(pUID);
    }
    catch (Exception e){
        e.printStackTrace();
    }
}

Note: br.mil.eb.dsgtools.formacombo is the ID of the desired combo instance (set in config.xml). I'm using Java, but hints can be in any language.


Edit

Apparently I found a way to grab ComboBoxes from within a Tool code. Solution is a code similar to the previous one, but it is now included inside the desired ComboBox implementation. Client tool should invoke this method to fetch the desired combo's instance.

public static DimCombo getExtension() throws UnknownHostException, IOException{
    if(s_extension == null){
        UID pUID = new UID();
        pUID.setValue("br.mil.eb.dsg.arctools.dimcombo");
        app.findExtensionByCLSID(pUID);
    }
    return s_extension;
}

Tool components need to do something like:

DimCombo combo = DimCombo.getExtension();

And then ComboBox methods are made available (like getSelected()).

But I am still with no solutions on making another ComboBox call the getExtension() like above. It gives a null pointer exception exactly at the above line.

So I still need some more help.

  • Does this answer help? gis.stackexchange.com/q/7517/43 The link to the add-in coding patterns seems informative. – Richard Morgan May 10 '17 at 17:22
  • In fact, it was not so helpful. I've created an extension to do some work, but I still don't know how to call the ComboBox from within that extension. – Diego Benincasa May 11 '17 at 14:55
  • Richard, your hint was of a little help, though. ComboBoxes do not initialize with the IApplication reference, so I've added an extension just to get it. My ComboBoxes now grab the reference from the extension, and the findExtensionByCLSID(pUID) can be used. – Diego Benincasa May 11 '17 at 18:24
  • Richard, I finally found the solution using extensions! Will post the solution right now. – Diego Benincasa May 11 '17 at 19:10
1

Finally I managed to workaround the problem, mainly using Richard's suggestion (comment in my original post).

So, for anyone looking for a solution to a problem like mine, here is the solution that worked for me.


ComboBoxes can't communicate directly with each other. Instead, it should be used an Application Extension addin. Extensions can communicate with any addin component inside the same project, considering that each component provides a method to retrieve its instance.

Using my problem as an example, let's take a look at the instance retrieval method for a ComboBox named FormaCombo:

public static FormaCombo getExtension() throws Exception{
    if(s_extension == null){
            UID pUID = new UID();
            pUID.setValue("br.mil.eb.dsg.arctools.formacombo");
            app.findExtensionByCLSID(pUID);
    }
    return s_extension;
}

(s_extension is a FormaCombo variable, declared at the beginning of class implementation.)

Take a look at app.findExtensionByCLSID(pUID). Here, app is a IApplication reference that ComboBoxes do not receive at their initialization methods. But since extensions do, we can get this reference from the extension and use inside the ComboBox, like this:

@Override
public void initialize() {
    s_extension = this;
    try{
        GabExtension gabExt = GabExtension.getExtension();
        FormaCombo.app = gabExt.appl;
    }
    catch(Exception e){}
}

(GabExtension is the name of my extension. It also have the getExtension() method like the ComboBox.)

Some remarks here:

  • Since components are singletons, getExtension() methods are static. Thus, app variables should also be static for every component (including the extension), in order to be used inside this method.
  • To pick app reference from the extension, it shouldn't be static. But it has to be static for the reason above. To solve this paradox, simply declare another IApplication variable, non-static, inside the extension, that picks the same value (IApplication appl = app - easy like that), and use this one. In my example code, FormaCombo has an IApplication variable named app, static, that gets the same value of appl, non-static, from the extension.

Now let's say we have a ComboBox named DimCombo (I'm using the names for my particular project) that has to do some work inside FormaCombo. To establish communication, every request should be passed to the extension, and from that to the other ComboBox. So, if we want to add a new item to FormaCombo based on the selection in DimCombo, this should do the trick:

public void onSelChange(int cookie){
    try {
        curSelect = cookie;
        Criterio crit = new Criterio();
        for(Criterio c: criterios){
            if(c.getIndex() == curSelect){
                crit = c;
                break;
            }
        }

        gabExt.formaComboClear();
        int const_circ = gabExt.addFormaComboItem("Circulo");
        gabExt.setFormaComboConstants(1, const_circ);
        if(crit.getTipo() == 2){
            gabExt.setFormaComboConstants(2, gabExt.addFormaComboItem("Quadrado"));
        }
        gabExt.setFormaComboCirculo();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Code is for my project, so let's focus on what is relevant here.

Note the gabExt.formaComboClear(), `gabExt.addFormaComboItem("Circulo") and other similar methods. All of them do some work in ComboBox FormaCombo - in fact, it asks the extension to do some job in the destination ComboBox.

Let's see how gabExt.formaComboClear() works:

public void formaComboClear(){
    try{
        formaCombo = FormaCombo.getExtension();
        formaCombo.clear();
    } catch(Exception e){
        e.printStackTrace();
    }
}

As you might have seen, it has nothing special; it just calls the FormaCombo clear() method. So why not doing this direcly from the other ComboBox? Because ArcObjects won't let you. This is the way to make things happen.

For the other methods, the behavior is similar.


Conclusion

If you want to make two addin components talk to each other, consider including an application extension addin to intermediate calls between them. Also, remember to include a getExtension() method similar to the example provided here, so the extension could find the components at runtime.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.