tags:

views:

53

answers:

2

Hi guys,

I searched for a sample for this, but could not find something that explains clearly how to set it up using RX: I have this requirement...

  1. In a WPF app, i have a list box
  2. A dispatcher timer routine adds some random numbers to a local List every say 2 seconds
  3. Now i want to setup an observable/observer to watch this List<int> as it keeps building up, and add the most recent number added, into the list box's items collection.

Sounds very simple, and i have done the third bit in a background thread (no RX, but with a standard lookup on list<int>)and added to the listbox easily. When trying to do the same without a background worker etc and just using RX, i am stuck.

Apologies for a possible stupid question (for you RX experts out there), but please help on how to get this WPF done using RX.

Thanks.

+1  A: 

I'm not entirely clear on what you're doing, but it sounds like List<int> is the problem here - it doesn't "natively" support Rx, in that it doesn't have any means of notifying observers when a new item is added.

When you subscribe to a List<int>, it will immediately just dump the current contents to the subscriber - it won't hang around and listen for extra changes.

Could I suggest that ObservableCollection<T> is probably more appropriate for you?

Jon Skeet
I see, Thanks Jon, so using OC<int> how do i do it then please. I am more interested in seeing the RX code in action. A simple sample will help... will be greatful to you. I am trying to get my heads around this cool RX thing...
Reader
@Reader: I'm afraid I don't have time to come up with an Rx example now, but have a look at the `ObservableCollection<int>.CollectionChanged` event.
Jon Skeet
Thanks i figured out a solution by trying out several things. I did not have to use an Observable Collection etc. I just used the extension method to get an IObservable (using AsObservable) out of a given IEnumerable (which the list of ints is), and subscribed to it, and all is fine. Thanks.
Reader
+5  A: 

When working with Rx you need to keep in mind the duality between IEnumerable<T> & IObservable<T> (as well as IEnumerator<T> & IObserver<T>).

You should always look for objects that implement IEnumerable<T> and consider how you would replace them with IObservable<T>.

In your question you say that you have a timer adding some numbers to a List<int> which you want to observe and add the new numbers to a list box. So I would consider replacing the list with an IObservable<int>. The trick here isn't about watching a list (or an ObservableCollection<int>) but instead it is about using Rx as a core part of your code.

So, here's a simple example.

Start with the core elements described in your question:

var dispatchTimer = new DispatcherTimer();
var random = new Random();
var listBox = new ListBox();

Create an observable from dispatchTimer:

IObservable<IEvent<EventArgs>> ticks =
    Observable.FromEvent(
        h => dispatchTimer.Tick += h,
        h => dispatchTimer.Tick -= h);

Query the observable to create a new observable of random numbers:

IObservable<int> randomNumbers =
    from tick in ticks
    select random.Next(1, 11);

Now, subscribe to the random numbers observable to update the list box:

_updateListBoxSubscription =
    randomNumbers.ObserveOnDispatcher().Subscribe(n => listBox.Items.Add(n));

The .ObserveOnDispatcher() call will make sure that the numbers are added to the list box on the UI thread.

You need to define a field or a property to hold a reference to the subscription so that it doesn't get garbage collected. This is exactly what event handler fields do when you add a handler, but with Rx you must explicitly do it.

private IDisposable _updateListBoxSubscription;

There you go - you now have a list box being updated from random numbers generated at the interval specified in the time.

It's that simple. I hope this helps.

Enigmativity
Excellent, thanks :) I will play around with this. Tnx for your time.
Reader
Good walk-through.
Bryan Anderson