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.