It’s a Small World, After All, part 1 – VB, C#, and GPS (Matt Gertz)

The title of this blog post has sort of a triple meaning for me.  First of all, I just got back from a long (and wonderful!) cruise in the Caribbean, followed by a stop at Disney World.  And of course, if you go to Disney World with kids, it’s the law that you have to go through the “It’s a Small World” ride, thereby having the accompanying song burned into your brain for the next six months.

Secondly, “It’s a Small World” also reminds me of how new technologies are bringing us closer together.  It’s amazing to me that I can do a full presentation in (for example) Asia without having to leaving my office.   For such scenarios to work, a number of different technologies have got to work together, and that’s tricky to get right.  In this blog post, I’m going to be working with both VB and C# and, while they are not really different technologies in the same sense as a phone and a video camera, it’s nevertheless very cool that you can work with both to achieve a cohesive “whole.”

Finally, in the third sense, “It’s a Small World” came to mind while I was working on my latest hobby project (which I’ll detail in this blog) – a GPS program for my Smartphone.  Verizon Wireless recently unlocked the GPS functionality for the Samsung Saga (one of which I own), and since I’ve always been really interested in GPS ever since it was made available to civilians, this was a great opportunity for me to jump in and try my hand at the GPS.  So, in this two-part series, I’ll be walking you through a GPS app which uses both C# and VB to support its functionality.

“Um, isn’t there already a GPS sample for Smartphones?”

Well, yes, and you can get it from the Windows Mobile 6 SDK, which you can download from here.  In fact, that’s where I’m going to start this project.  (This will work on both VS2005 and VS2008, by the way.)

If you download the SDK and run the C# “GPS” sample (not the “Mobile GPS” sample; that’s for C++), you’ll see that it’s pretty simple.  There are two pieces; a class library which wraps the native GPS calls into managed calls, and a mobile application which displays the GPS info.  The UI for the mobile application is very simple – there is a menu item to exit the program, another menu item pair to start and stop the GPS, and a label.  The GPS device generates the events, the UI handles them and appends the text to the label – that’s it.  It’s a good place to start, but it really doesn’t fit a daily usage bill.  I want my GPS program to always display at-a-glance:

·         The state of the GPS

·         The number of satellites in the solution and how many of those are available

·         Latitude and longitude – both in DMS and DM format (since many geocaching sites are given in DM format)

·         My altitude

·         My velocity (speed and direction)

·         A way to specify a target location, and the distance/direction to it.

That’s a lot to cram onto a phone screen – but I managed to fit it in. (I plan on adding more later, particularly a way to mark locations and cache them to use as targets later, but this is a good start.)  Here’s how I went about it:

Creating a new GPS UI

First, open the GPS sample solution (if you haven’t already) and remove the “GpsSample” project.  (You might want to create a copy of the solution first, so that you have the old one for reference.)  We’re going to write a new, better UI that uses VB instead, so add a VB Smart Device Project to the solution, calling it “VBGPS” or something like that.  (Right-click the solution, choose “Add Project,” “Visual Basic,” “Smart Device,” type in “VBGPS” for the name, and press OK.)  In the next dialog, select the “Device Application” project type and press “OK.”

In the new project, you’re going to need to add a reference to the Microsoft.WindowsMobile.Samples.Location class library, so right-click the VBGPS project and choose “Add Reference…”  Navigate to the “Projects” tab and select the aforementioned class library, then press “OK.”  Now, you are hooked up to the C# code which wraps the native GPS functionality.

Double-click “Form1” in the VBGPS” project to bring up the form (if it’s not visible already).  In the property grid, change the FormFactor property to match the form factor of your phone.  (I have a square screen on my phone, so I’ve chosen “Windows Mobile 6 Professional Square.”)  You can also change the Text of the form to something like “VBGPS” so that the title of the window doesn’t say “Form1.”

Now, we’ll start adding controls.  First, we’ll add the menu controls.  These will be the same as the C# version of the sample.  The menu control already exists by default, so click on the left-hand bottom menu and change its text to “Exit” in the property grid – you can also give the control a better name (e.g. “ExitMenuItem”) if you like.  Click on the right-hand bottom menu and change its text to “GPS,”  again changing the control name if you like (e.g. “GPSMenuItem”).  With “GPS” still selected, click the “Type Here” above it and add two menu items – “Start GPS” and “Stop GPS.”  While each is selected, change their control names to something more intuitive in the property grid (e.g. “StartGPSMenuItem” and “StopGPSMenuItem” respectively).

Now, we’ll add the labels and such.  For the following functionality, I’ll drag out two labels – one for the name of the GPS property, and one next to it to contain its value:

·         Status

·         Satellites

·         Lat (i.e., latitude)

·         Long (i.e., longitude)

·         Alt (i.e., altitude)

·         Vel (i.e., velocity)

Status and Satellites should share a line (for a total of four labels on one line); the others have a line each to themselves.  All of them should be set to 8pt font in order to fit on the screen, and the value labels should have meaningful names set for them in the property grid.  (I used “StatusLabel,” “SattLabel,” “LatLabel,” “LongLabel,” “AltLabel,” and “VelLabel.)

We also want to be able to specify a target location.  So, farther down on the form, we’ll drag out a label and change its text to “TargetLat:”.  To the right of it, we add three small text boxes – these will hold degrees, minutes, and seconds.  Finally, to the right of those, we’ll drag out a small combo box.  In the property grid, make sure its Type is “DropDownList,” and in the Items collection, add “N” and “S” as possibilities.  All of these controls should be set to 8pt fonts using the property grid, and all of the text and combo boxes should have meaningful names.  (I chose “LatDegTB,” “LatMinTB,” “LatSecTB,” and LatPosCB.)

Now, we’ll select the entire line of controls and, while holding down the “Control” key, drag a new copy of them below the existing ones.  These will be the longitude target controls, so make the appropriate name and text changes in the copies, and also change the copied combo box items to “E” and “W.”

Finally, we’ll add two more label pairs below that like we did at the beginning.  One will be for “Distance” and the other for “Direction” – make sure that the value labels have good names like “DistLabel” and “DirLabel.”

That’s the UI.  It just barely fits on the screen, and it we want to add any more functionality, we’d have to bring up another window.  But this will get us going, so let’s write some code.

The C# code

First, let’s make a few changes in the class library.  As I mentioned above, we’re going to keep the class library as a C# endeavor.  There’s no reason why it couldn’t be changed to VB code, but since it’s just a bunch of wrappers and they all work pretty well, there’s no need to invest the time to change the code.  However, there are a couple of helper methods that I want to either change or add, and they (will) exist in the DegreesMinutesSeconds helper class defined in DegreesMinutesSeconds.cs.  (We’ll get back to VB code shortly.)

DegreesMinutesSeconds is a class that allows for easy manipulation of latitude and longitude data.  Not only does it store a particular coordinate, but it gives you two ways to interact with the data – as pure degrees (e.g., -82.673529) or as degrees/minutes/seconds (e.g., -82° 40’ 24.7044”).  In this model, North and East are positive values; West and South are negative values.

This is all well and good, but I like to go geocaching, and in geocaching the coordinates are often described in terms of degrees and minutes (e.g., -82° 40.41174’).  I would like to therefore support that format as well.  Currently, the members of this class are:

uint degrees;               /// In VB, this would be Private degrees As UInteger

uint minutes;               /// In VB, this would be Private minutes As UInteger

double seconds;      /// In VB, this would be Private seconds As Double

and each of these have properties associated with them; for example:

        public uint Degrees /// VB: ReadOnly Property Degs() As UInteger

        {

            get { return degrees; } /// VB:  Get: Return degrees: End Get

        }

 

However, we want to be able to express coordinates that have a fractional minute, and so we add the following:

        double dminutes;

        public double DMinutes

        {

            get { return dminutes; }

        }

 

Now we have to use it.  There are already a couple of constructors, and we’ll need to fix them up to set dminutes  – additions are underlined.  The code is close enough to VB that I won’t bother providing a helpful translation in the blog – just remember that “(uint) x” is equivalent to “CUInt(x)”, etc:

public DegreesMinutesSeconds(double decimalDegrees)

        {

            isPositive = (decimalDegrees > 0);

            degrees = (uint)Math.Abs(decimalDegrees);

            dminutes = (Math.Abs(decimalDegrees) – Math.Abs((double)degrees)) * 60.0;

            minutes = (uint)dminutes;

            seconds = (dminutes – (double)minutes) * 60.0;

        }

 

public DegreesMinutesSeconds(bool isPositive, uint degrees, uint minutes, double seconds)

        {

            this.isPositive = isPositive;

            this.degrees = degrees;

            this.minutes = minutes;

            this.seconds = seconds;

            this.dminutes = minutes + seconds / 60.0;

        }

 

I also need to add an entirely new constructor to take decimal minutes as an argument:

public DegreesMinutesSeconds(bool isPositive, uint degrees, double dminutes)

        {

            this.isPositive = isPositive;

            this.degrees = degrees;