Where Am I?

Where am I? Display your current position on map. We use GeoCoordinateWatcher and cover emulating this using Reactive Extensions.

Setup

Before jumping into the tutorials head to developer.windowsphone.com to download the free tools and get them installed.

This tutorial is going mostly cover using the GPS that’s mandated to be part of Windows Phone 7, there used to be some problems with this in that it was hard to simulate GPS activity through the emulator. We’ll cover how you can use the new development tools to emulate the GPS or how to use Reactive Extensions to do something similar.

All the code for working with the GPS resides in the assembly System.Devices (this mimics the namespace for the same functionality on Windows 7). So the first thing you’ll need to do is add a reference. Since we’ll be using the Microsoft Reactive Extensions framework you’ll need to add references to System.Observable and Microsoft.Phone.Reactive.

What we’re going to do is wrap the actual GPS in a Reactive Extensions Observable, this’ll allow us to switch out the actual observable for our generated one.

The important class for the GPS is GeoCoordinateWatcher, it has two methods - Start and Stop and two events, PositionChanged and StatusChanged. We’ll start by creating two fields for the page, a GeoCoordinateWatcher and a Random for emulation.

private readonly Random random = new Random();

private readonly GeoCoordinateWatcher geoCoordinateWatcher = new GeoCoordinateWatcher();

Reactive Extensions are a great library that provides Linq style operations over asynchronous and event based operations, you can read a lot more about it on the RX Team blog. To create an observable around the GeoCoordinateWatcher we use the static method Observable.FromEvent passing information about how to subscribe and unsubscribe from the event, we then use a Select operation to remove some of the cruft since we’re only interested in the position. Then we start the watcher and return the observable.

private IObservable<GeoCoordinate> CreateObservableGeoPositionWatcher()
{
    var observable = Observable.FromEvent<GeoPositionChangedEventArgs<GeoCoordinate>>(
        e => geoCoordinateWatcher.PositionChanged += e,
        e => geoCoordinateWatcher.PositionChanged -= e)
        .Select(e => e.EventArgs.Position.Location);

    geoCoordinateWatcher.Start();

    return observable;
}

For the emulation we start with a very simple method that creates a random GeoCoordinate. In our create emulator method we use the Observable.Timer method to create an observable collection that will push values at a regular pace, we then use Select to create random coordinates.

private IObservable<GeoCoordinate> CreateGeoPositionEmulator()
{
    return Observable.Timer(TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(10))
        .Select(l => CreateRandomCoordinate());
}

private GeoCoordinate CreateRandomCoordinate()
{
    var latitude = (random.NextDouble() 180.0) - 90.0;
    var longitude = (random.NextDouble() 360.0) - 180.0;

    return new GeoCoordinate(latitude, longitude);
}

We now have two different methods each returning similar observable collections. So in the OnLoaded method we select which method to use and use the Subscribe method to hook up the OnPositionChanged method to whenever the observable collection pushes us a new coordinate. One other very important thing is the ObserveOnDispatcher method, because both the real GPS and our fake timer push their events on a background thread we need to marshal the call back the UI thread so that we won’t receive an exception when updating the UI.

private void OnLoaded(object sender, RoutedEventArgs e)
{
    var useEmulation = true;

    var observable = useEmulation ? CreateGeoPositionEmulator() : CreateObservableGeoPositionWatcher();

    observable
        .ObserveOnDispatcher()
        .Subscribe(OnPositionChanged);
}

private void OnPositionChanged(GeoCoordinate location)
{
    Latitude.Text = location.Latitude.ToString();
    Longitude.Text = location.Longitude.ToString();

    Map.Center = location;
}

When the position changes we simply update the two text blocks and the map.

Mango Update: New in the Windows Phone 7.1 SDK is the ability to emulate the GPS using the emulator tools, this is a much needed change and somewhat invalidates the requirements in this tutorial. However I’d still highly recommend playing with Reactive Extensions.

Download the Code

The code for all the tutorials is available to download: Windows Phone 7 Tutorials Solution.