This post is really just a design addendum to my previous post, an opportunity to revisit and redress the solution I presented for the problem of converting GPS data directly into US based Zip Code and while technically correct, I really did spend much time discussing or considering the the nature and architecture of the Windows Phone. In fact part of my solution would lead directly to poor phone performance, and so I wanted to take a couple of moments and discuss one of the fundamental differences in the approach of using and consuming services for WP7.

Lets consider the archetypal example where a button calls a service and that service returns some simple result. There are several ways to accomplish this using the WP7, however, you are guided toward a “pit of success” by being subtlety pushed toward the event driven model. In the traditional service call model you make a call and literally wait for the service to return some kind of result.

Waiting for the service to return the result with a potentially unreliable internet connection could lead to long wait times which in turn could produce a very inconsistent and unresponsive UI experience. Also note that this version of WP is a single threaded environment (it may change in the future) so we cannot offload this work to some background thread. What we can do is some simple event driven programming (you remember “call backs” from back in the day single proc PC days, same concept) which would look like this:

private void StartLocationButton_Click(object sender, RoutedEventArgs e)
{
  // The watcher variable was previously declared as type GeoCoordinateWatcher. 
  if (watcher == null)
  {
    watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High); // Use high accuracy.
    watcher.MovementThreshold = 20; // Plus or Minus 20m, helps ignore noise in the signal.
    watcher.StatusChanged += 
	new EventHandler(watcher_StatusChanged);
  }
  watcher.Start();
}
void watcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e)
{
  Dispatcher.BeginInvoke(() => MyStatusChanged(e)); //Call BeginInvoke as discussed below…
}
void MyStatusChanged(GeoPositionStatusChangedEventArgs e)
{
  if (e.Status == GeoPositionStatus.Ready)
      // Use the Position property of the GeoCoordinateWatcher object to get the current location.
      GeoCoordinate co = watcher.Position.Location;
      LatitudeTextBlock.Text = e.Position.Location.Latitude.ToString("0.000");
      LongitudeTextBlock.Text = e.Position.Location.Longitude.ToString("0.000");
      //Stop the Location Service to conserve battery power.
      watcher.Stop();
  }
}

For those of us coming from the Web world there is a subtle “hoop” that is easily forgotten that is critical to Windows GUI programming i.e. only the thread that created a control can subsequently access and/or modify its contents (there are a couple of exceptions). Any attempts to update controls from other threads will result in unpredictable behavior and downright weird UI results. Whenever you need to update a control from a thread that did not initially create it, you need to wrap the call within a BeginInvoke call as show above (see Line 14).

Related Posts: