October 26, 2009 1 Comment
A scenario that comes up for me quite often is the need to pass information from a form to a command or tool and vice versa. At first it seemed a difficult task because I wasn’t all that familiar with COM programming and was under the impression that COM objects were some sort of special entities that somehow functioned differently from normal objects. This really was a misconception on my part. While it is true that COM classes are a special type of class and their implementation differs from normal object classes, they are still at heart normal object classes. The same is true for Form classes. All that is needed to pass information from one class to another is a property or method and there is no reason why you can’t add your own to COM classes and forms alike.
The sample project that accompanies this article contains a sample dialog with two buttons. The first demonstrates how to pass information from a form to a custom ArcMap command. The second shows how to pass information from a custom ArcMap tool to a form.
Looking at the code behind the first button, you’ll see that we are calling a custom command that performs a fixed zoom in operation. This custom command is similar to the built-in Fixed Zoom In command found in ArcMap. The difference is that our custom command allows the zoom factor to be specified, thus changing how much the map is zoomed. Looking at the implementation of the custom command you’ll see that it has a property named ZoomFactor. The trick to gaining access to this property is shown in the form code. The code gets a reference to the command by calling ICommandBars::Find(). We can get a reference to the underlying ICommand object from ICommandItem::Command. Because this reference is typed as ICommand we need to cast to the actual class type of our command class. Once we’ve done this we have access to the ZoomFactor property. We can then set the property and call Execute() to run the command.
An alternative method of doing this would be to create a custom interface that defines the ZoomFactor property and have our command class implement this interface in addition to implementing ICommand. This would certainly keep more to the COM model than simply defining the property directly on the class but it isn’t really necessary. If you have a set of properties and methods that you want to be common across multiple command and tool classes, then you might want to consider using a custom interface to ensure consistency. Otherwise you may find it simpler to do it as shown.
The second example demonstrates how to pass information from a tool to a form. Looking at the code behind the button you’ll see that it is calling a custom select features tool similar to the one shown in my last article. The difference here is that this tool will update the calling form to display the number of selected features. In order to do this, the tool class will need a reference to the form. Looking at the tool class you’ll see that a property has been added to allow the form reference to be set. This property is set in the form code the same way as in the previous example. Looking at the form class you’ll see a method has been added that will update the label text on the form using the value passed in as a parameter. The code in the custom tool calls this method after the features have been selected and passes in the selection count.
The real trick here is getting a reference to the form. In this particular example it’s easy because the tool is being called from the form in question. All we have to do is pass that instance of the form. A more common scenario requires updating a form displayed by another command or tool class. In this case you will need to add a property to that command or tool that will return an instance of the form it displays. The code in the tool class that needs to update that form will first need to get a reference to the command or tool that displays the form. This is done by calling ICommandBars::Find() just like we did in these two examples. Once you have that command or tool reference you can get the form reference from the property you added and pass it to your custom tool.
As with anything else in the programming world there are other solutions than these but I think the two we have demonstrated here are relatively simple and easy to understand. Hopefully this will get you thinking about how individual components can work together within your applications.