(X) Hide this
    • Login
    • Join
      • Generate New Image
        By clicking 'Register' you accept the terms of use .

Using Reactive Extensions in Silverlight

(17 votes)
Pencho Popadiyn
>
Pencho Popadiyn
Joined Apr 30, 2008
Articles:   22
Comments:   97
More Articles
16 comments   /   posted on Mar 03, 2010

This article is compatible with the latest version of Silverlight.

This is part 1 of the series “Reactive Extensions in Silverlight”.

1. Introduction

One of the coolest features which is part of .NET Framework and also available for Silverlight applications is the RX Framework. The arising interest around the RX Framework made me roll up my sleeves and start playing around this.
So the first step was to answer several important questions such as: “what is Linq to Events?”, “what is RX Framework?”, and “what is Reactive Programming?” And generally what lies behind these sound terms? Linq to events or RX Framework (also known as Reactive Extensions for .NET Framework) is one and the same designation for a library for composing asynchronous and event-based programs using observable collections. Ok, this is the official description, but it sounds pretty academic and initially it didn’t give me any understanding about the RX Framework. The next step was to watch several introduction videos on Channel 9; they helped me to understand better the meaning (the idea) of the framework.

Take a look at the next code snippet:

Image010 

How many times have you done this in your application? Consider for a moment the collections in .NET Framework; they are all unified by IEnumerable. Arrays, lists, they all implement the IEnumerable interface. If you take a look at these collections, they are pulling collection. If you are using a loop, you receive the data from a collection over a period of time, or in other words, you are pulling the data, saying “move next, move next”, pulling the elements out.

Image020

What we have here is an implementation of the Iterator pattern (IEnumerable\IEnumerator).

Now, if we take a look at the RX style collection, they are push collections. They push values to you. And here is another key moment to understand. What does “push values to you” mean? Take a look again at the next code snippet. It represents another very common situation in the programming, namely, the usage of events.

Image030

We are handling the MouseMove event. This is a pretty standard task. The mouse cursor’s location value is changing over a period of time, and an event notifies you about that - or in other words, the source is pushing values to you. If we again refer to the design patterns, we will see that we have an implementation of the Observer pattern. Yes, the centerpiece of the RX Framework is the Observer pattern. All RX style collections are unified by the IObservable interface. You can then subscribe to this observable using an instance of an object implementing the IObserver interface. 

On one side – we have the Iterator pattern ( IEnumerable<T>\IEnumerator<T>)  and on the other side we have the Observer pattern (IObservable<T>\IObserver<T>). The interesting point here is that the RX developers consider the IObservable<T> as a mathematical dual to the IEnumerable<T> interface. Normally, any Enumerable collection can be turned into Observable collection and vice versa. Basically the RX Framework consists of two interfaces - IObservable<T> and IObserver<T>. Just like the Enumerable collections where you can perform various LINQ operations, the same are implemented for the Observable collections.
So if you have to remember something, it's that the Enumerable collections are pulling data from the source and the Observable collections are pushing data from the source. And any Enumerable collection can be turned into an IObservable collection and vice versa.

Ok, But what can be done with the RX Framework?

Probably, each time I am playing with a new technology, the part that is most difficult for me is to put the technology into practice. What kind of problems can be solved with the RX Framework? In fact the RX Framework doesn’t solve problems that were unsolvable in the past, but it offers new, different and sometimes easier ways to approach existing problems:

  • Asynchronous programming. RX provides you with a built-in threading support and lets you observe collections in background threads.
  • Composing custom events. This is probably the most exciting feature of the RX Framework (at least for me). Imagine a drawing application. The most common tasks in such sort of applications are to select, draw and modify objects. The core part of these behaviors is the mouse and keyboard interaction, combining mouse buttons, implementing dragging operations, etc. The RX Framework addresses these issues.
  • RX offers two new interfaces: IObservable<T> and IObserver<T>. You could create observable from existing event and enumerable, use it as a regular CLR class.

Enough words, let’s take a look at some demos. Before proceeding you could download the source code for the demos from here.

Download source code

The RX Framework can be downloaded from here.

2. From IEnumerable<T> to IObservable<T>

We can start with something simple. As I said in the introduction, any “enumerable collection can be turned into observable collection”. Let’s see what this means. For the first demo I am using two simple ListBoxes, which are populated in the code-behind. You could check the source code for this example in the Demo1 folder of the Demo Solution.

<Grid x:Name="LayoutRoot" Background="White">
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <ListBox x:Name="lbEnumerable"/>
    <ListBox x:Name="lbObservable"
             Margin="10"/>
</Grid>
 
The first ListBox is populated through a foreach loop.
 
List<string> products = new List<string>
{
    "Chai", "Chang", "Aniseed Syrup", "Konbu", "Tofu", "Geitost"
};
foreach ( var item in products )
    this.lbEnumerable.Items.Add( item );
 
And now the interesting part – the RX Framework exposes a ToObservable() extension method, which turns an IEnumerable collection into an IObservable collection.
 
IObservable<string> observable = products.ToObservable();
 
Once you have an Observable you can subscribe in the following fashion:
 
observable.Subscribe<string>(
    p =>
    {
        this.lbObservable.Items.Add( p );
    } );

The result from the previous code-snippet is that the lbObservable ListBox is populated with items thanks to the reactive framework, which pushes values to you (to the ListBox).
Another interesting extension method is Repeat(), which repeats the observable sequence “n” times. Or even more, you can repeat sequences indefinitely.

IObservable<string> observable = products.ToObservable().Repeat(10);

The result is that all products will be pushed to the ListBox ten times.
There are several overloads of the Subscribe method. One of them accepts a delegate which is executed when the observable sequence ends.

observable.Subscribe<string>(
    p =>
    {
        this.lbObservable.Items.Add( p );
    }, () =>
    {
        this.lbObservable.Items.Add( "-----Completed----" );
    } );

And the result is:

Image050

3. Unsubscribing from Observables

An important issue is to be able to unsubscribe from the observer. Take a look at the Repeat() example again. And for some reason you would like to create an indefinite sequence.

IObservable<string> observable = products.ToObservable().Repeat();

The result from the above example is that the observable collection will push elements to the observer infinitely. Each time the Subscribe() method is called, it returns an IDisposable objects that can be used to unsubscribe and to stop pushing elements to the observer, like this:

IDisposable disposable = observable.Subscribe<string>(
    p =>
    {
        this.lbObservable.Items.Add( p );
    }, () =>
    {
        this.lbObservable.Items.Add( "-----Completed----" );
    } );
//....
disposable.Dispose();
 

4. Turning Events into Observables

This is one of the coolest features of the RX Framework. The Observable object exposes a FromEvent () static method, which can be used to turn an event into an observable. After that, the event can be used as any other regular object in your application.You could check the source code for this example in the Demo2 folder of the Demo Solution.

var mouseMoveEvent = Observable.FromEvent<MouseEventArgs>( this, "MouseMove" );

And of course you could subscribe to the observable of the mouse move event in the familiar fashion.

mouseMoveEvent.Subscribe(
    p =>
    {
        // Do something when the mouse 
        // moves around the screen
    } );

 

This is pretty simple and couldn’t illustrate the power of the RX Framework. You could attach to the mouse move event in the standard and old school manner.

Image030

But let’s complicate the situation a little bit. Imagine that you want to update the text box only when you are moving the mouse around the screen and in the same time the left mouse button is down. Which means that if you use the standard approach for attaching to events, you should have an additional Boolean flag which is raised each time the left mouse button is pressed and to reset it when the left mouse button is released. Take a look at how this can be handled using reactive extensions. The only thing you should do is to create observables from the MouseMove and MouseLeftButtonDown events, and to combine them using the SkipUntil() extension method.

var mouseMoveEvent = Observable.FromEvent<MouseEventArgs>( this, "MouseMove" );
var mouseLeftButtonDown = Observable.FromEvent<MouseButtonEventArgs>( this, "MouseLeftButtonDown" );
var events = mouseMoveEvent.SkipUntil( mouseLeftButtonDown );
// Subscribe to the events

The final step is to stop observing, when the mouse left button is released. Again this can be done in the same manner – we are observing the MouseLeftButtonUp event. However, this time the TakeUntil() extension method will be used.

var mouseMoveEvent = Observable.FromEvent<MouseEventArgs>( this, "MouseMove" );
var mouseLeftButtonDown = Observable.FromEvent<MouseButtonEventArgs>( this, "MouseLeftButtonDown" );
var mouseLeftButtonUp = Observable.FromEvent<MouseButtonEventArgs>( this, "MouseLeftButtonUp" );
var events = mouseMoveEvent.SkipUntil( mouseLeftButtonDown ).TakeUntil( mouseLeftButtonUp ).Repeat();
events.Subscribe(
    p =>
    {
        Point mousePosition = p.EventArgs.GetPosition( this );
        tbMousePosition.Text = String.Format( "Mouse position {0}, {1}",
            mousePosition.X, mousePosition.Y );
    } );
What we have here is that the text block is updated only when the mouse is moving and the left button is pressed. We will stop updating the text box when the mouse left button is released.

Image080 

5. Drag and Drop

Now, as we have some basic knowledge about the reactive extensions, lets create the equivalent of the “Hello World” for RX, namely, this is a drag and drop application. At the first moment I said: “wow drag and drop, this is not simple”. But you’ll see how easy it could be with RX.

To begin, I’ll add a TextBox and Image inside a Canvas. You could check the source code for this example in the Demo3 folder of the Demo Solution.

<Canvas>
    <TextBlock x:Name="textBlock"
             Text="Drag Me!!!"
             FontSize="20"
             Canvas.Top="10"
             Canvas.Left="10"/>
    <Image Source="/RXDemos;component/SilverlightShow.png"
           Canvas.Top="50"
           Canvas.Left="10"
           x:Name="image"/>
</Canvas>
 
Image060
 
Next, turn the MouseLeftButtonDown, MouseMove and MouseLeftButtonUp events into observables.
 
var mouseMoveEventImage = Observable.FromEvent<MouseEventArgs>( image, "MouseMove" );
var mouseLeftButtonDownImage = Observable.FromEvent<MouseButtonEventArgs>( image, "MouseLeftButtonDown" );
var mouseLeftButtonUpImage = Observable.FromEvent<MouseButtonEventArgs>( image, "MouseLeftButtonUp" );

You can create a new observable to listen for a sequence of mouse positions – starting when the mouse left button goes down, and then listening to all positions in mouse move, until the mouse left button goes up.

var draggingEventsImage = mouseMoveEvent.SkipUntil( mouseLeftButtonDown ).
    TakeUntil( mouseLeftButtonUp ).Repeat();
 
As I mentioned in the introduction, you could turn an event into observable and treat it as any regular CLR object. Which means that you could write LINQ queries against it. Now check this out.
 
var draggingEventsImage = from pos in mouseMoveEventImage.SkipUntil( mouseLeftButtonDownImage ).
                              TakeUntil( mouseLeftButtonUpImage )
                        .Let( mm => mm.Zip( mm.Skip( 1 ), ( prev, cur ) =>
                            new
                            {
                                X = cur.EventArgs.GetPosition( this ).X - 
                                    prev.EventArgs.GetPosition( this ).X,
                                Y = cur.EventArgs.GetPosition( this ).Y - 
                                    prev.EventArgs.GetPosition( this ).Y
                            } ) ).Repeat()
                          select pos;

What I am doing here is simply taking the delta between the previous position and the current position, while the mouse is being dragged. The Zip functions merge two observables sequences into one observable sequences by using a selector function.
Finally, subscribe to the dragging events and set the new position of the image.

draggingEventsImage.Subscribe(
    p =>
    {
        Canvas.SetLeft( image, Canvas.GetLeft( image ) + p.X );
        Canvas.SetTop( image, Canvas.GetTop( image ) + p.Y );
    } );

You could do exactly the same for the TextBlock or any other control inside the canvas.

6. Drawing with RX

Considering the previous drag and drop demo, now we can examine another common issue that is addressed by the RX Framework. You could create drawing application in the same manner, as in the drag and drop demo. You could check the source code for this example in the Demo4 folder of the Demo Solution.

var mouseMoveEvent = Observable.FromEvent<MouseEventArgs>( this, "MouseMove" );
var mouseLeftButtonDown = Observable.FromEvent<MouseButtonEventArgs>( this, "MouseLeftButtonDown" );
var mouseLeftButtonUp = Observable.FromEvent<MouseButtonEventArgs>( this, "MouseLeftButtonUp" );
var draggingEvents = from pos in mouseMoveEvent.SkipUntil( mouseLeftButtonDown ).
    TakeUntil( mouseLeftButtonUp )
                        .Let( mm => mm.Zip( mm.Skip( 1 ), ( prev, cur ) =>
                            new
                            {
                                X2 = cur.EventArgs.GetPosition( this ).X,
                                X1 = prev.EventArgs.GetPosition( this ).X,
                                Y2 = cur.EventArgs.GetPosition( this ).Y,
                                Y1 = prev.EventArgs.GetPosition( this ).Y
                            } ) ).Repeat()
                     select pos;
draggingEvents.Subscribe(
    p =>
    {
        Line line = new Line();
        line.StrokeThickness = 2;
        line.Stroke = new SolidColorBrush( Colors.Black );
        line.X1 = p.X1;
        line.Y1 = p.Y1;
        line.X2 = p.X2;
        line.Y2 = p.Y2;
        this.LayoutRoot.Children.Add( line );
    });

 

Image065

7. Asynchronous Programming with RX – the PI Calculator

Asynchronous programming is by no means restricted to Web scenarios. But not anymore, RX is ideal for composing async applications.
Let’s say that the value of PI in System.Math.PI, at only 20 digits, isn’t precise enough for you. In that case, you may find yourself writing an application that calculates pi to an arbitrary number of digits. Although this may not be a real world example, it will illustrate the idea of handling asynchronous programming with RX. Probably many of your applications need to perform long-running operations (e.g.: printing, web service call, or calculation).

You could check the source code for this example in the Demo5 folder of the Demo Solution.

Image070

Check out the method, which is responsible for the pi calculation.

static IEnumerable<CalculationData> Calculate( int numberOfDigits )
{
    for ( int i = 0; i < numberOfDigits; i += 9 )
    {
        int nineDigits = NineDigitsOfPi.StartingAt( i + 1 );
        int digitCount = Math.Min( numberOfDigits - i, 9 );
        string ds = string.Format( "{0:D9}", nineDigits );
        yield return new CalculationData( ds.Substring( 0, digitCount ), 
            i + digitCount );
    }
}

As you know, any IEnumerable collection could be turned into IObservable collection, and could be observed in a background thread.

IObservable<CalculationData> digits = Observable.ToObservable<CalculationData>( 
    Calculate( this.InputDigitsCount ) );
 
digits.Subscribe<CalculationData>(
    item =>
    {
        if ( String.IsNullOrEmpty( this.Output ) )
            this.Output = "3.";
 
        this.Output = String.Concat( this.Output, item.NextDigits );
    }, () =>
    {
        this.IsCalculationInProgress = false;
    } );


8. Final Words

The RX Framework doesn’t solve any unsolvable problems, but it could be really useful. It offers you a different approach for any existing problems. I hope that this article has offered you a good overview of the RX Framework, although any of the fundamentals are not covered.

9. References

  • http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx
  • http://channel9.msdn.com/tags/Rx/

Subscribe

Comments

  • -_-

    RE: Using Reactive Extensions in Silverlight


    posted by Donald on Mar 05, 2010 09:07

    I'm still confused on some aspects of this. I thought that I could click a button to products.Add("Test") and it would automatically be added to the list since it was being 'observed'.  I even tried moving the products and observable to a high scope so they would go out of scope.  I guess this is not what I want.
    Would be nice to see how I could add to a list on a background thread data that comes from a web service and see the new data added to added to say a list control.  I think it would be good for notifications.

    I tried running the calculation with 10000 digits. During that the drag drop was too slow to work well.

  • -_-

    RE: Using Reactive Extensions in Silverlight


    posted by Donald on Mar 05, 2010 09:31
    By the way, great article.. cleared up alot.  I got notthing out of the ch9 videos.
  • -_-

    RE: Using Reactive Extensions in Silverlight


    posted by miantosca on Mar 05, 2010 15:15
    great article - watched the ch9 videos a while ago but this article did a better job of explaining how
    you might use it so simplify otherwise very complex problems.
  • ppopadiyn

    RE: Using Reactive Extensions in Silverlight


    posted by ppopadiyn on Mar 05, 2010 20:00

    Hi Donald

    Straight to first question. I beleive products.Add("Test") will no longer work, when the observable sequence ends (the Completed event is raised). What you need to do is to write something like this:

    IObservable<string> observable = Observable.Return<string>( "Test" );
    observable.Subscribe<string>(
        p =>
        {
            lbObservable.Items.Add( p );
        } );

    The second question (about the web services) is pretty interesting, and this is common issue for Silverlight. I'll try to prepare a small demo and will update the article.

    @miantosca , thanks for the nice words.

  • -_-

    RE: Using Reactive Extensions in Silverlight


    posted by Donald on Mar 06, 2010 03:02

    I'm feel led astray by the words. I'm expecting that if I make something observable it will be observed... even if I add something later. If I subscribe it should do some work until I unsubscribe.  Maybe some clarification in this area would help.  It seems that the event stuff is the true observation/subscription work. 

  • -_-

    RE: Using Reactive Extensions in Silverlight


    posted by Donald on Mar 06, 2010 03:30
    A killer demo would be to have a duplex WCF service push notifications from the server to a silverlight background thread, then have the observable stuff update the UI.
  • -_-

    RE: Using Reactive Extensions in Silverlight


    posted by Fallon Massey on Mar 06, 2010 10:16

    I've looked at this stuff 6 ways to Sunday, but this is the FIRST article that made it make any sense to me.

    GREAT Stuff!!!

  • -_-

    RE: Using Reactive Extensions in Silverlight


    posted by Keith Dahlby on Mar 06, 2010 17:54

    One tip for "chatty" events like MouseMove is to use Throttle() to only capture one event per time interval (every 100ms, for example).

    Cheers ~
    Keith

  • -_-

    RE: Using Reactive Extensions in Silverlight


    posted by Florim Maxhuni on Mar 07, 2010 15:35
      Very interesting post, and RX will be more interesting for me if will be more posts like this.
  • ppopadiyn

    RE: Using Reactive Extensions in Silverlight


    posted by ppopadiyn on Mar 07, 2010 21:52

    @Keith, thanks for tip

    @Florim, you won't have to wait too long, the next post is comming the next week ( RX + Web services ).

  • -_-

    RE: Using Reactive Extensions in Silverlight


    posted by Bobby Diaz on Mar 11, 2010 10:32

    Great article!  Thanks for sharing.  By the way, after I read your article, I played around with a way to cut down on the amount of code needed to subscribe and combine multiple IObservables.  Check out my blog post:

    http://blog.bmdiaz.com/archive/2010/03/11/generate-strongly-typed-observable-events-for-the-reactive-extensions-for.aspx

    Thanks!

  • -_-

    RE: Using Reactive Extensions in Silverlight


    posted by Tim Greenfield on Mar 25, 2010 00:44

    Great article! For drag and drop operations you ought to call CaptureMouse and ReleaseMouseCapture right? I'm not sure what the best way to accomplish this is but one way that I got to work was:

     

     

    from pos in mouseMove.SkipUntil(mouseLeftButtonDown.Do((o) => this.CaptureMouse())).

     

    TakeUntil(mouseLeftButtonUp.Do((o) => this.ReleaseMouseCapture()))

  • ppopadiyn

    RE: Using Reactive Extensions in Silverlight


    posted by ppopadiyn on Mar 25, 2010 12:09

    Hi Tim,

    Another possible way, to do drag and drop is to use mouse offsets instead of mouse deltas. For example, the code that I am using in the article could be changed to this:

    var mouseDown = from evnt in Observable.FromEvent<MouseButtonEventArgs>( image, "MouseLeftButtonDown" )
                    select evnt.EventArgs.GetPosition( image );
    var mouseUp = Observable.FromEvent<MouseButtonEventArgs>( image, "MouseLeftButtonUp" );
    var mouseMove = from evnt in Observable.FromEvent<MouseEventArgs>( image, "MouseMove" )
                    select evnt.EventArgs.GetPosition( this );

    var query = from offset in mouseDown
                from position in mouseMove.TakeUntil( mouseUp )
                select new
                {
                    X = position.X - offset.X,
                    Y = position.Y - offset.Y
                };

    query.Subscribe(
        point =>
        {
            Canvas.SetLeft( image, point.X );
            Canvas.SetTop( image, point.Y );
        } );

     

  • -_-

    RE: Using Reactive Extensions in Silverlight


    posted by Bell End on Apr 01, 2010 13:00
    This comment has been removed, because of inappropriate content.
  • -_-

    RE: Using Reactive Extensions in Silverlight


    posted by Mads Lee Jensen on May 21, 2010 09:51
    Thanks for this great post, watched some of the chn9 vidoes but didnt get the point of Rx this did a much better job. I wish i found this post before i saw the chn9 videos! then they probably would have made more sense!
  • -_-

    RE: Using Reactive Extensions in Silverlight


    posted by RichardS on Oct 31, 2010 16:06
    Great article. I learnt more from spending twenty minutes reading your article than from spending five hours watching the ching the Channel 9 Rx videos. Those Channel 9 guys could learn a lot about how to teach new concepts from YOU !!

Add Comment

Login to comment:
  *      *       

From this series