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.
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: