65.9K
CodeProject is changing. Read more.
Home

Implementing the GeoCoordinateWatcher as a Reactive Service

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0 vote)

Jan 2, 2013

CPOL

2 min read

viewsIcon

19074

With Rx, events are first class citizens that can be passed around and composed as needed in a very simple way.

With Rx, events are first class citizens that can be passed around and composed as needed in a very simple way.

The Reactive Extensions (Rx) is a library for composing asynchronous and event-based programs using observable sequences and LINQ-style query operators. Using Rx, developers represent asynchronous data streams with Observables, query asynchronous data streams using LINQ operators, and parameterize  the concurrency in the asynchronous data streams using Schedulers. Simply put, Rx = Observables + LINQ + Schedulers.” – from the MSDN page.Paulo Morgado

The library also provides a considerable amount of helpers that make it easy to warp events into observables.

Wrapping the GeoCoordinateWatcher as a reactive service is quite simple. All it takes is creating observables and exposing the events as observables:

public class GeoCoordinateReactiveService : IGeoCoordinateReactiveService, IDisposable
{
    private readonly GeoCoordinateWatcher geoCoordinateWatcher = new GeoCoordinateWatcher();

    public GeoCoordinateReactiveService()
    {
        this.StatusObservable = Observable
            .FromEventPattern<GeoPositionStatusChangedEventArgs>(
                handler => geoCoordinateWatcher.StatusChanged += handler,
                handler => geoCoordinateWatcher.StatusChanged -= handler);

        this.PositionObservable = Observable
            .FromEventPattern<GeoPositionChangedEventArgs<GeoCoordinate>>(
                handler => geoCoordinateWatcher.PositionChanged += handler,
                handler => geoCoordinateWatcher.PositionChanged -= handler);
    }

    public IObservable<EventPattern<GeoPositionStatus> StatusObservable { get; private set; }

    public IObservable<EventPattern<GeoPosition<GeoCoordinate>> PositionObservable { get; private set; }
}

And now, instead of the StatusChanged and PositionChanged events we have respectively the StatusObservable and PositionObservable as a stream of EventPattern<TEventArgs> instances.

But the EventPattern<TEventArgs> class includes the source of the event and an the event arguments in properties which is far more than we need in this case. With normal LINQ operators we can convert the streams of EventPattern<TEventArgs> instances in streams of the desired values.

public class GeoCoordinateReactiveService : IGeoCoordinateReactiveService, IDisposable
{
    private readonly GeoCoordinateWatcher geoCoordinateWatcher = new GeoCoordinateWatcher();

    public GeoCoordinateReactiveService()
    {
        this.StatusObservable = Observable
            .FromEventPattern<GeoPositionStatusChangedEventArgs>(
                handler => geoCoordinateWatcher.StatusChanged += handler,
                handler => geoCoordinateWatcher.StatusChanged -= handler)
            .Select(ep => ep.EventArgs.Status);

        this.PositionObservable = Observable
            .FromEventPattern<GeoPositionChangedEventArgs<GeoCoordinate>>(
                handler => geoCoordinateWatcher.PositionChanged += handler,
                handler => geoCoordinateWatcher.PositionChanged -= handler)
            .Select(ep => ep.EventArgs.Position);
    }

    public IObservable<GeoPositionStatus> StatusObservable { get; private set; }

    public IObservable<GeoPosition<GeoCoordinate>> PositionObservable { get; private set; }
}

And to use these observables all it is needed is to subscribe to them:

geoCoordinateWatcherService.StatusObservable
    .Subscribe(this.OnStatusChanged);

geoCoordinateWatcherService.PositionObservable
    .Subscribe(this.OnPositionChanged);

But, usually, we want to use these values in view model to bind to the UI and, consequently, we want this to happen in the UI thread:

geoCoordinateWatcherService.StatusObservable
    .ObserveOnDispatcher()
    .Subscribe(this.OnStatusChanged);

geoCoordinateWatcherService.PositionObservable
    .ObserveOnDispatcher()
    .Subscribe(this.OnPositionChanged);

It’s as simple as that!

Resources: