Creating a Custom Code Library

As programmers, we are expected to write code that is efficient, readable, and scalable. There are quite a few things that we can do to meet these expectations from using design tools to adopting code standards to using code analysis tools. One thing that you can do to improve your overall development process is to create your own code libraries. There are many benefits to this. The most obvious benefit is it reduces the time you spend writing code as you don’t waste time writing the same code over and over.

Another benefit is centralization. If you’ve been following my previous articles you’ve probably noticed there are several classes that have been included in each of the sample projects. By including these classes, we’ve eliminated the need to keep writing that code each time we want to use it. However, what if we found a bug in that code? As it stands now, we would have to fix the bug in each project that contains the class. If we had instead put those classes into a common code library we would only have to fix the bug in one place, saving us a lot of time while ensuring that the same fix is applied in each project. The same would be true if we decided to extend one of those classes to add new functionality.

Creating your own code libraries is relatively easy to do. The most important thing is to give it some thought before you get started and design a system that will work best for you. I’ll spend the rest of this article going over some of the things we here at GISi came up with when implementing the code libraries that we use for our projects. There is also a sample project that you can download that demonstrates some of these ideas.

Before getting started, there are a few things to think about. First and foremost is what your library (or libraries) will be used for. Here at GISi, we develop both web and desktop solutions so we created 3 separate libraries. One library is for web development, one is for desktop (Windows) development, and the other is a common library that can be used for both. This makes sense for two reasons. First, web development and desktop development are very different from each other so it really makes sense from a logical standpoint to separate the two. The second is a technical reason. The web classes will most likely reference the ESRI web assemblies and the desktop classes will most likely reference the ESRI desktop assemblies. If we didn’t separate the two, then our library would require both ArcGIS Server and ArcGIS Desktop to be installed on the client machines. This is certainly not feasible so we really had no choice but to create two libraries. We then created a third common library that doesn’t reference any ESRI assemblies and contains classes that are compatible in both environments.

The first step is creating the code project. Open Visual Studio and create a new project, choosing Class Library as the project type. Choose the name of this project carefully as it will be with you for a long time and changing the name after you’ve deployed it a few times could be troublesome. After you’ve created the project, it’s time to start adding your classes.

We use namespaces to organize the classes in our libraries. This is how the .NET Framework is structured so we thought it would be good for consistency to do the same. It is a good idea from a technical standpoint because it allows us to create globally unique types which are important when it comes to deploying the library. It seemed only natural for our root namespace to be GISi. You can set the root namespace for each of your code libraries on the Application tab of the Project Properties page.

It is common practice to organize the class files in your project by using folders that mimic the namespaces defined by your class model. Since we created 3 libraries, we created a namespace for each library. We created GISi.Web, GISi.Windows, and GISi.Common. This way we can tell which code library our classes belong to without having to look them up. Each of our code libraries contains an appropriate root folder.

You may decide that you need to further organize your classes within your code library. For our Windows library we needed several levels of organization to keep things from feeling cluttered. For example, all classes dealing with user interfaces go into GISi.Windows.UI and all classes dealing with ArcObjects go into GISi.Windows.ArcObjects. Since we have many classes dealing with ArcObjects we further organize them according the to ArcObjects library they primarily use. So, our code library contains classes in GISi.Windows.ArcObjects.Carto, GISi.Windows.ArcObjects.Display, and several others. You are certainly not required to do it the same way but I just wanted to mention it so that you’d be aware of it and could use this information when planning your own libraries.

So let’s take a look at the sample project and see some examples of what I’ve just been talking about. If you look at the Application tab in the Project Properties you’ll see that the Root Namespace has been set to CodeLibrary. This will be the root for all of the classes in the library. You’ll also see that there have been several folders added to the solution. These folders mimic the namespaces used by the classes they contain. For example, if you look at the code module for the TabProcessorDialog you will see the namespace has been declared as Windows.UI and if you look at the MapHelper class you will see its namespace has been declared as Windows.ArcObjects.Carto. This is very important and is something you will need to do for all of the classes that you add to your library if you want your classes to be organized into namespaces. Note that the namespaces defined in the classes do not include the CodeLibrary root. This is because the root namespace you defined at the project level will be applied to all of the classes when the project is compiled.

I think it’s also important to mention that all of the classes contained within a namespace do not have to be in the same code project or solution. Each of our code libraries has its own code project contained within its own solution yet all of them use GISi as their root namespace. As long as you define the namespace in your class code it does not matter where that class is located.

The sample project is pretty simple but should be enough to get you started. The classes it contains are simplified versions of the same classes that we use in our own projects. In future articles I’ll go over how we use these code libraries in our projects and how we handle deploying them. Future sample projects will also contain this code library and I’ll probably be adding a class or two as we go along. 

Additions to the GISi Team

GISi is proud to announce the addition of three new employees to the company:  Zac Odom, Matt Sheehan and Nadav Epstein. Read more of this post

Communicating Through Events

In my last article I discussed one method of passing information between components within an application. This method requires that you create properties and methods on your object classes that can be called from the various components at runtime. In certain scenarios, this method isn’t possible or is tedious at best. For example, let’s say we have an application for creating and managing widgets. We have created two commands. One allows the user to create new widgets and the other displays a dialog that lists all of the widgets that the user has created. While designing our application we decide that it would be nice if the dialog that lists the widgets would automatically update each time a new widget is created. This way, the user doesn’t have to close the dialog and re-open it in order to see the new widget in the list.

Our first instinct might be to use the method I discussed last time and create an Update method on the list dialog that would refresh the list. This method could be called by the Create Widget command each time a new widget is created. While this solution would certainly work, it’s not really the most elegant solution. As our application grows, we may add more ways to create widgets or add more dialogs that list widgets. If this happens, it would mean we would have to go back and modify our current Create Widget command to update all of the new dialogs that list widgets. It would also mean that we would have to remember to call the Update method on our current List Dialog each time we implement a new way of creating a widget. As you might imagine, it won’t be long before we will be spending hours writing code that ensures all of our components are communicating with each other properly. This is something we’d like to avoid if at all possible.

A better solution would be to create a custom event that is fired each time a widget is created. Our Create Widget command would fire this event when the widget is created and the Widget List dialog would subscribe to this event and update every time it fires. In the future, any new methods of creating a widget that we add would simply fire this same event and any dialogs that need to list the widgets would simply subscribe to this event. We wouldn’t have to go back and modify any of our existing components. Using this solution, we can create an application that is easily scalable with minimal effort.

The sample project that accompanies this article demonstrates the scenario I’ve just described. Upon opening the project you’ll see we have a class named Widget that defines what a widget is. For demo purposes, it will simply be an object with a name. The WidgetEvents class defines what events will be available. For the time being, we’ll just define events for creation and deletion. The WidgetCreated event will receive a reference to the widget being created through its event arguments. The WidgetDeleted event will receive the name of the widget being deleted. Note how these arguments are defined via custom event argument classes. This is the key to passing information through events. You can create custom argument classes that allow you to pass whatever information you want. Also note that the WidgetEvents class has a method that fires each of the events. The components within the application will call these methods whenever they need to fire an event.

Our application will need a central instance of the WidgetEvents class that can be accessed by the individual components. Extensions are an easy way to provide this type of thing. The WidgetExtension class implements IExtension and provides a reference to the WidgetEvents class.

The project also contains two command classes that show two dialogs. The Widget dialog creates new widgets. See the code behind the Create button to see how it creates the new widget, assigns it to a new instance of the event arguments class, gets a reference to the extension, and calls the method on the WidgetEvents class to fire the WidgetCreated event. The Widget Manager dialog lists the widgets that have been created. Note how it declares the event listener WithEvents and sets the reference in the form’s Load event. Note also how the WidgetCreated event handler has been implemented. When you compile and run the application, you should be able to show both dialogs by adding the commands to a toolbar and clicking them. Type in a new name on the Widget dialog and click Create. You should see the Widget Manager dialog update almost immediately with the name of the new widget.

This sample provides the bare bones of how to communicate with events. As mentioned earlier, the WidgetDeleted event has been declared but, as you may have noticed, isn’t implemented in the sample. As an exercise, you might want to take a shot at implementing it. If you aren’t familiar with creating and using your own custom events then I think you’ll find them to be a powerful tool that you may want to start using.