Entries:
Comments:
Posts:

Loading User Information from Channel 9

Something went wrong getting user information from Channel 9

Latest Achievement:

Loading User Information from MSDN

Something went wrong getting user information from MSDN

Visual Studio Achievements

Latest Achievement:

Loading Visual Studio Achievements

Something went wrong getting the Visual Studio Achievements

Writing your first Rx Application

Download

Right click “Save as…”

  • WMV (WMV Video)
  • MP3 (Audio only)
  • MP4 (iPhone, Android)
  • Mid Quality WMV (Lo-band, Mobile)
Today we released Reactive Extensions for .NET on DevLabs.

Rx is a .NET Library that allows programmers to write succinct declarative code to orchestrate and coordinate asynchronous and event-based programs based on familiar .NET idioms and patterns.


In this video, Wes Dyer goes through the steps of writing your first Rx Application. The Hello World equivalent of Rx is Drag-and-Drop.

Tags:

Follow the Discussion

  • ChevalN2Cheval Why not null?

    Just wow!

     

    One question, how well does this play with WPF triggers?

  • Thanks for making this video.  Can you please post the code for this sample app?  My vision is too poor to be able to read any of the code in the video.

  • Very cool! Really shows the expressive, declarative nature of Rx. Big improvement over the way we normally do things.

     

    How about a video showing asynchronous programming via Rx? 

  • Allan LindqvistaL_ Kinect ftw

    did you check out the wmv high version? text is much clearer there Smiley

  • Allan LindqvistaL_ Kinect ftw

    triggers are based on dependency properties, and you could write something that makes a dependecy property into an observable

    im working on something like that infact Smiley

     

    also @wes, Observable.Context is static, what if i want to have one observable use one context and another observable to use another?

  • Allan LindqvistaL_ Kinect ftw

    -edit-

    this discussion continued on the rx forums where a neater solution was found

    -end edit-

     

    Hello again, i wrote a little helper class for converting dependency properties to Observable, im not sure its the best way to do it though, what do you guys think? am i missing something? There are some anonymous Observable/disposable in rx that i'd liked to use but they are internal.. i suspect there is something smarter i can do with the Create methods but i coudnt get around making a helper class..

     

    public partial class MainWindow : Window {
      public MainWindow( ) {
      InitializeComponent( );
      Observable.Context = SynchronizationContext.Current;
      this.ActualHeightAsObservable( ).Subscribe( d => label1.Content = d );
      }
    }
    public class DependencyObservable<T> : IDisposable {
      EventHandler eh; DependencyPropertyDescriptor des; object instance;
    
      public DependencyObservable( IObserver<T> observer, DependencyProperty dp, Type ownertype, object ins ) {
        des = DependencyPropertyDescriptor.FromProperty( dp, ownertype );
        instance = ins;
        eh = new EventHandler( ( o, e ) => observer.OnNext( ( T )des.GetValue( instance ) ) );
        des.AddValueChanged( instance, eh ); 
      }
    
      public void Dispose( ) {
        des.RemoveValueChanged( instance, eh ); 
      }
    }
    public static class WindowExtensions {
      public static IObservable<double> ActualHeightAsObservable( this MainWindow w ) {
        return CreateWithDisposable<double>( obs => new DependencyObservable<double>( obs, MainWindow.HeightProperty, 
          w.GetType( ), w ) )
      }
    }
    

     

    The nice thing is that the returned observable respects all the rules of Dependency properties, if the dp is changed by a style, trigger or binding, the Observable should reflect that (ive only tried with bindings though)

  • Michael A. VolzFlynn0r Passionate about code

    This video makes it very clear what Rx is capable of. Thanx a lot

  • @aL_, use .SubscribeOn and .ObserveOn expect more work in the future on this area...

  • does RX work with asp.net applications too ?

  • Rx is a general purpose library, should work fine in asp.NET, just make sure you don't set the Observable.Context to a UI context (the default context in .NET 3.5 SP1 & .NET 4 Beta 2 is the Reactive EventLoop which should work fine for ASP.NET).

  • Allan LindqvistaL_ Kinect ftw

    i tried them but i must have made some mistake because i got the cross thread excepitons anyway.. i tried having them both before and after the assignment to the label but no luck :/

    can you give an example perhaps?

  • Amazing! Erik Meijer is a programming God!

  • Joshua RossJoshRoss Drinking Ovaltine since 2004

    What am I doing wrong?  This doesn't do anything.

     

    Public Class Form1
     Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
      Observable.Context = System.Threading.SynchronizationContext.Current
      Dim xs = Observable.Interval(TimeSpan.FromSeconds(1))
      xs.Subscribe(Function(y) Me.Text = y.ToString)
     End Sub
    End Class

  • try setting Observable.Context = System.Threading.SynchronizationContexts.WindowsForms

  • If both your observables update the UI, they should both run in the UI context, can you send out a sample of what is going wrong?

  • Allan LindqvistaL_ Kinect ftw

    the code i posted before does work Smiley

    however this:

    Observable.Return( 10 ).SubscribeOn( SynchronizationContext.Current ).Subscribe( d => label1.Content = d );

    or this:

    Observable.Return( 10 ).SubscribeOnWindowsForms( ).Subscribe( d => label1.Content = d );

    or this:

    Observable.Return( 10 ).SubscribeOnDispatcher(this.Dispatcher ).Subscribe( d => label1.Content = d );

     

    doesnt work for some reason. they all fail with a cross thread exception in the label1.Content setter, the rest of the program is just an empty wpf app with a label

  • Richard Anthony HeinRichard.Hein Stay on Target

    I tried exactly the same thing in VB and in C#, and guess what?  The VB version doesn't work, but the C# version does!  Scared

    The only difference is the way the Form_Load handler is hooked up.

    Ok, I was wrong before, but the real problem is that Me.Text = y.ToString is being treated as a boolean comparison:

     

    Reflector:

     

    <CompilerGenerated> _
    Private Sub _Lambda$__1(ByVal y As Long)
        Dim flag1 As Boolean = (Me.Text = "asdfasdf")
    End Sub
    
  • Joshua RossJoshRoss Drinking Ovaltine since 2004

    Twas the night before Christmas, when all through the house
    Not a creature was stirring, not even an observable.
    The context was set by the chimney with care,
    In hopes that a subscription would soon would be there.

     

    Sorry, Jeff.  Any other guesses?

  • Joshua RossJoshRoss Drinking Ovaltine since 2004

    My man Richard! Nice find.  This leave me with another mystery.  When I put the same code inside a button_click event, it also does nothing.  I guess the head in the box does not use vb.net.

  • I tried it out and it seems that the anonymous functions in VB are getting in the way.  If you write it without anonymous functions then it works fine.  The reason is that assignment is a statement and so cannot be an expression and therefore not in an anonymous function.  Instead, the = becomes the equality operator so each time the interval fires it checks to see if the form's text is equal to the current textual representation of the interval's value: obviously wrong.

     

    Here is the fix:

    Imports System.Threading
    Public Class Form1
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Observable.Context = SynchronizationContexts.WindowsForms
            Dim xs = Observable.Interval(TimeSpan.FromSeconds(1))
            xs.Subscribe(AddressOf Foo)
        End Sub
        Private Sub Foo(ByVal X As Long)
            Me.Text = X.ToString
        End Sub
    End Class
    

  • Richard Anthony HeinRichard.Hein Stay on Target

    This does work.

    Private Function SetText(ByVal text As Object)
     Me.Text = text.ToString()
     Return Me.Text
    End Function

    Private Sub Form1_Load_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Me.Load
     Observable.Context = System.Threading.SynchronizationContext.Current
     Dim xs = Observable.Interval(TimeSpan.FromSeconds(1))
     xs.Subscribe(Function(y) SetText(y))
    End Sub

  • Richard Anthony HeinRichard.Hein Stay on Target

    Yes, I can definitely verify that's the case.  Bug!

  • Joshua RossJoshRoss Drinking Ovaltine since 2004

    It gets worse, that is an illegal cross thread call.  So, I have to either disable checking, or have a private field and invoke some update method.  Or, maybe this is a side effect of running the app in x64 in the debugger.  Either way, this is not good.  I thought of overloading the = operator, but that is even more confusing.

  • Did you set the Observable.Context correctly?

     

    What does the code look like?

  • Joshua RossJoshRoss Drinking Ovaltine since 2004

     

    Public Class Form1
     Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
      'uncomment this to disable ictc checking
      'Control.CheckForIllegalCrossThreadCalls = False
      Observable.Context = Threading.SynchronizationContexts.WindowsForms
      Dim theAnswer = Observable.Return(42)
      theAnswer.Subscribe(Function(monkeyDo) MonkeySee(monkeyDo))
     End Sub
     Private Function MonkeySee(ByVal monkeyDo As Long) as Boolean
      Me.Text = monkeyDo.ToString
      Return Me.Text = monkeyDo.ToString
     End Function
    End Class
    

     

    EDIT: It looks like I'll have to eat my hat.  That function should be a sub.  Or did I just stumble across something completely different?  That's why I love tomorrow, because tomorrow is another day!  I'm going to bed.

     

    EDIT:  I just ran it on 2010 and noticed that the thread that hits foo is a worker thread.

     

    Public Class Form1
        Private meText As String
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Observable.Context = Threading.SynchronizationContexts.WindowsForms
            Dim o = Observable.Return(42)
            o.Subscribe(AddressOf foo)
        End Sub
        Public Sub foo(ByVal bar As Long)
            meText = bar.ToString
            Invoke(New MethodInvoker(AddressOf UpdateMeText))
        End Sub
        Public Sub UpdateMeText()
            Me.Text = meText
        End Sub
    End Class

     

    EDIT:  If I use Observable.Context = Threading.SynchronizationContexts.CurrentDispatcher, my threads are in order.  Bug #2.

  • Richard Anthony HeinRichard.Hein Stay on Target

    Is this a VB bug or an Rx bug then?  Am I going to get my lunch with Eric?  Smiley

  • Unfortunately, it has nothing to do with Rx.  And if you reported it as a VB bug then the VB team would correctly say that it is by design.  Which probably means that it is a bug in the user code.

     

    Now, understandably this is a rather confusing bug, and I tend to think that overloading "=" to be either relational equality or assignment leads to some rather interesting cases and so I personally think that VB is rather confusing here.

  • Tsuo Kang Chentkchen7 Tsuo Kang Chen

    LINQ plus Rx...Cool!!!

  • Hi guys!

    I've problems with the sample from this video. Current Rx version has no Observable.Context property. Could you please tell me how this code should be rewritten? I played with SubscribeOn....

    var xs = Observable.Interval(TimeSpan.FromSeconds(1)). SubscribeOn(SynchronizationContext.Current);
    xs.Subscribe(value => TextBlock.Text = value.ToString());
    

    , but still have exception 'The calling thread cannot access this object because a different thread owns it'.

     

    Thanks

  • Manual helped. ObserveOn has to be used instead.

    var xs = Observable.Interval(TimeSpan.FromSeconds(1)); 
    xs.ObserveOn(SynchronizationContext.Current).Subscribe(value => TextBlock.Text = value.ToString());
    

  • DonaldBydia Donald

    How can the same sample be done in Silverlight?
    1. I discovered I do not need the Observable.Context.
    2. the MouseEventArgs do not contain a definition of StartWith.

     

    Is there any site that has samples like:
    The WPF way:
    The Silverlight way:
    The Winform way:
    ????

  • The code as shown in the screen cast does not work as others have commented because Observable.Context has been removed. Would it not make sense to repost the screen cast reflecting the changes to the API to avoid causing pain to all who look at this screen cast and find that their code is broken? 

  • noematanoemata Noemata

    For the March 2010 release of Rx, the code needs to be adjusted as follows:

     

            public Window1()
            {
                InitializeComponent();

                var xs = Observable.Interval(TimeSpan.FromSeconds(1)).StartWith(-1);

                var mouseDown = from evt in Observable.FromEvent<MouseButtonEventArgs>(this, "MouseDown")
                                select evt.EventArgs.GetPosition(this);

                var mouseUp = from evt in Observable.FromEvent<MouseButtonEventArgs>(this, "MouseUp")
                                select evt.EventArgs.GetPosition(this);

                var mouseMove = from evt in Observable.FromEvent<MouseEventArgs>(this, "MouseMove")
                                select evt.EventArgs.GetPosition(this);

                var q = from start in mouseDown
                        from delta in mouseMove.StartWith(start).TakeUntil(mouseUp)
                        .Let(mm => mm.Zip(mm.Skip(1), (prev, cur) =>
                            new { X = cur.X - prev.X, Y = cur.Y - prev.Y }))
                        select delta;

                q.ObserveOnDispatcher().Subscribe(value =>
                    {
                        Canvas.SetLeft(image, Canvas.GetLeft(image) + value.X);
                        Canvas.SetTop(image, Canvas.GetTop(image) + value.Y);
                    });
            }

  • Hi Wes,

     

    I suspect there's a problem with the automatic invocation of Dispose when OnCompleted is called, when we use Linq-to-Rx. Details:

     

    The MSDN Library has an example for using IObservable here: http://msdn.microsoft.com/en-us/library/dd783449(v=VS.100).aspx"> http://msdn.microsoft.com/en-us/library/dd783449(v=VS.100).aspx. There the EndTransmission method of the observable (LocationTracker) makes a copy of the observers collection (using ToArray) before calling

    OnCompleted on each observer. It has to create this copy because the OnCompleted method is followed by an automatic call to Dispose.

    [This automatic call happens only when we subscribe to the output of a LINQ method such as Select etc, and not directly subscribe to the

    LocationTracker object (the original observable).] And Dispose removes the observer from the observers collection, so we get the exception “Collection was modified; enumeration operation may not execute.” on the next iteration in the foreach in OnCompleted. To prevent this the MSDN example uses a copy of the observers collection.

     

    The problem with this approach is that an unnecessary copy is created solely to facilitate removal of the observer from the collection member variable. However, notice right there that the last line of EndTransmission is a call to observers.Clear(). So why not leave the work of clearing the collection to the observable class and you (the RX framework) avoid making the call to Dispose internally? That way we wouldn't have to make a copy of the observers collection and at the same time be able to use foreach in EndTransmission.

     

    The observer class here (LocationReporter) has one string member variable instName (apart from the Unsubscriber reference). Making copies of a large number of observers makes that many unnecessary copies of these member variables. Since (from your videos) the sole purpose of Dispose here seems to be unsubscribing, we don't need to call Dispose here because the mass unsubscription is anyway achieved by the observable when it calls observers.Clear() in EndTransmission.

     

    What are your thoughts on this?

     

    -Venkatesh

  • There is no longer an Observable.Context.. I got this working with the following code

     

    var xs = Observable.Interval(TimeSpan.FromSeconds(1));
    xs = xs.ObserveOnDispatcher<long>();
    xs.Subscribe(value => textBlock.Text = value.ToString());
    

Remove this comment

Remove this thread

close

Comments Closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums,
or Contact Us and let us know.