Reactive Extensions (Rx) - Part 7 - Sample Events

Reactive Extensions
  1. Reactive Extensions (Rx) - Replacing C# Events
  2. Reactive Extensions (Rx) - Wrapping C# Events
  3. Reactive Extensions (Rx) - Naming Conventions
  4. Reactive Extensions (Rx) - Replacing Timers
  5. Reactive Extensions (Rx) - Awaiting Observables
  6. Reactive Extensions (Rx) - Task ToObservable
  7. Reactive Extensions (Rx) - Sample Events
  8. Reactive Extensions (Rx) - Timeouts

Its been a while since I've done another Rx post. They've been pretty popular and thanks to the community for all the positive feedback. I was talking to a colleague yesterday who had been using standard C# events in WPF (The principals learned in this post can apply anywhere). He had subscribed to the TextChanged event in C# and was updating the user interface on the fly, whenever the user typed in a character of text. He was getting way too many events being fired and his user interface couldn't keep up with all the work it was being asked to do.

this.TextBox.TextChanged += this.OnTextBoxTextChanged;

private void OnTextBoxTextChanged(object sender, TextChangedEventArgs e)
{
    // Heavy User Interface updates that can cause the application to lock up.
}

This is a very common scenario which I myself have come across several times. The solution to this problem is to take a sample of the events being fired and only update the user interface every few seconds. This is possible without Reactive Extensions (Rx) but you have to write a fair amount of boilerplate code (I know, I've done it myself).

Reactive Extensions (Rx) can do this with a few easy to understand (This is the real bonus) lines of code. The first step is to wrap the WPF TextChanged event (I've shown how to do this in a previous post here).

public IObservable<TextChangedEventArgs> WhenTextChanged
{
    get
    {
        return Observable
            .FromEventPattern<TextChangedEventHandler, TextChangedEventArgs>(
                h => this.TextBox.TextChanged += h,
                h => this.TextBox.TextChanged -= h)
            .Select(x => x.EventArgs);
    }
}

this.WhenTextChanged
    .Sample(TimeSpan.FromSeconds(3))
    .Subscribe(x => Debug.WriteLine(DateTime.Now + " Text Changed"));

The final and most succinct step is to use the Sample method to only pick out the latest text changed event every three seconds and pass that on to the Subscribe delegate. It really is that easy and this blog post really is this short because of that!

Web Mentions

What's this?

0 Replies

GitHub Comments

RehanSaeed

Roland Pheasant Roland Pheasant commented on 2015-01-06 13:48:34

This is promising to be a great tutorial series on RX. I think in many ways a lot of the rx guru's overly complicate rx so much so that many people are put off and bewildered. In future I will point people here.

Do you know about this http://dynamicdataproject.wordpress.com/

RehanSaeed

Muhammad Rehan Saeed Muhammad Rehan Saeed commented on 2015-01-06 14:02:19

This is promising to be a great tutorial series on RX. I think in many ways a lot of the rx guru's overly complicate rx so much so that many people are put off and bewildered. In future I will point people here.

Do you know about this http://dynamicdataproject.wordpress.com/

I had a lot of trouble learning Rx myself. These articles are my way of trying things out and seeing what works best. I'm still learning BTW.
The problem is, Rx is really that complicated! It can do so much but there is a massive amount of overlap with other API's. So although it can do so much, it doesn't mean you should use it.
I think when you cut out the bits you shouldn't use it for, it's a really great API.

I've not come across that project, I'll give it a read when I get a chance.

RehanSaeed

Roland Pheasant Roland Pheasant commented on 2015-01-06 15:30:50

I had a lot of trouble learning Rx myself. These articles are my way of trying things out and seeing what works best. I'm still learning BTW.
The problem is, Rx is really that complicated! It can do so much but there is a massive amount of overlap with other API's. So although it can do so much, it doesn't mean you should use it.
I think when you cut out the bits you shouldn't use it for, it's a really great API.

I've not come across that project, I'll give it a read when I get a chance.

I agree there is a steep learning curve but once the penny drops then it is full steam ahead. I personally find coding without it now to be alien.

RehanSaeed

Muhammad Rehan Saeed Muhammad Rehan Saeed commented on 2015-01-06 15:41:01

I agree there is a steep learning curve but once the penny drops then it is full steam ahead. I personally find coding without it now to be alien.

Totally agree. Its just like Linq. Losing it is like losing an arm.