Saturday, July 31, 2010

Developing COM Components to Plug Into ArcMap - My Noobie Problems

After my initial experience writing the War card game in VB and C#, I've decided to try and stick with C# for the remainder of GEOG 489. The problem with this is that while the IDE is the same, I've quickly found differences in working with ArcObjects in C# vs. VB.

No COM Class Template

The first major difference I found was that C# does not have a built-in COM Class template. Duh! Luckily within about 10 minutes I found one at Oren Ellenbogen's blog which was written for C# 2005, but it seems to be working just fine for 2008. I place the zip file in 'Visual Studio 2008\Templates\ItemTemplates\Visual C#' and it worked like a charm.

No Stub

The next issue that I ran into was that for some reason C# was not generating the stub code for implementing the ICommand interface. I had noticed this on the last project, but had simply brute forced it because there were relatively few methods to implement. This time I learned that if you right-click on the window, you can tell the IDE to stub out the methods:


In my opinion, if you have to write out all the stub code then you might as well be working in notepad.

ArcMap Don't See My Component

After writing the code to create the custom zoom button, I had a more frightening problem of not seeing the command category appear in ArcMap. I was worried that this might take a while to troubleshoot, but I quickly discovered a couple of issues that may have been the source of my problem. The key to solving them was finding a long tread on the bytes.com forums discussing a similar problem. I believe that the key to solving my problem was:
  • Adding a blank constructor to the class (seemed pretty logical)
  • Going to Project -> Properties "Build" tab and selecting the "Register for COM Interop" option
These steps resolved my problem. I was then able to see the "Geog 489" category in ArcMap and the zoom tool worked with no problem.

No Modules in C#

When starting section III of the project, I was surprised that there was no option to add a "module" in the add item dialog. I soon realized that the idea of Modules is not part of C#, instead everything must be in its own class. In figuring out the best achieve a similar solution for re-using code (DRY...don't repeat yourself...or even better DIE...duplication is evil), it stumbled upon a forum thread discussing this exact issue. The post recommends creating a public sealed class. I found this worked well and I made the Zoom method static so I could call the function without actually instantiating the class. Here's what the class looks like:

Tuesday, July 20, 2010

Welcome to War...

During week one of PSU's application development class, we got VB2008 express installed and began exploring Visual Studio. The goal of the week was to create a text version of the popular card game war using a basic windows form. The project was great start for learning VB because there were enough situational contexts to become familiar with common code logic and syntax.

This was my first experience with .NET and it had been a since my last encounter with VBA. I found VB 2008 to be fun, but wordy. Needing to add endtags (ex. EndIf) and logical opertors as words( ex. "If not" instead of "!="). The IDE does handle a good amount of the labor, the extra characters add additional clutter to the page.

After completing the project, I decided to download C#2008 express and see if that was any better. I took my VB project and started re-writing the code. It helped that the IDE layout was the same and the C# syntax is reminiscent of actionscript. In no time I had my interfaces, card, deck, and war classes ready to go. Here are some code highlights:

In the VB interfaces, the user defines read-only / write-only accessors explicitly, followed by property/method name and type.

Module Interfaces
Interface ICard
WriteOnly Property Number() As Integer
ReadOnly Property Rank() As String
ReadOnly Property Description() As String
ReadOnly Property Suit() As String
ReadOnly Property Value() As Integer
End Interface

Interface IDeck
ReadOnly Property CardsLeft() As Integer
Sub Shuffle()
Function DealCard() As Card
End Interface
End Module

In C# interfaces it is the opposite. The user firest defines type, then the property/method, and finally implicitly indicates read-only/write-only accessors through getter/setter methods.
namespace Cards_CSharp
{
public interface ICard
{
// Property declarations
int number {set;}
int value {get;}
string rank {get;}
string description {get;}
string suit {get;}
}

public interface IDeck
{
// Method declarations
void openDeck();
void shuffle();
ICard dealCard();
}
}

Both VB and C# implement the appropriate getters/setters to obey the interface, but I found the C# syntax to be easier:

Public Class Card
Implements ICard
Private m_intCardNum As Integer
Public WriteOnly Property Number() As Integer Implements Interfaces.ICard.Number
Set(ByVal value As Integer)
If value > 0 And value <>
m_intCardNum = value
End If
End Set
End Property

The VB class attaches the interface property name explicitly to their respective implementation (ex. public property ... implements Interfaces.ICard ...). I decided to opt-out of this for the C# version. Instead the interface is specified in the class definition and the compiler lets me know if I've missed a property.

class Card : ICard
{
private int _intCardNum;
public Card()
{
}

public int number
{
set
{
_intCardNum = (value > 0 && value <>
}
}

On the final line of code, I use an inline if statement. I think these sorts of statements can get dangerous if too many conditionals are aggregated together. But in this case, I felt it was cleaner and not hard to follow. The general structure for an inline conditional is:

property = ( if this statement is true ) ? true value : else false value ;

Deck- One of the key methods for the game was Deck.shuffle(). In that

Overall I preferred the coding of the game in C#, but so far I'm not crazy about the IDE. I found Visual Studio to be a bit cluttered with tools, wizards and alert boxes. I should probably invest some time in learning the short-cut keys, as using the menu options is tedious (ex. stop debugger). I thought that the design view was convenient for control layout, but not for defining their names (ids). Also I couldn't figure out how to tab code in VB to get a straight vertical columns of code.