Friday 24 February 2012

Asynchronous actions with RX

I was trying to come up with a syntactically tidy way to run some code in the ThreadPool.

Assume I have a function as follows that performs the work:

void PopulateIsolatedStorageList()
{
using (iso = IsolatedStorageFile.GetUserStoreForApplication())
{
string[] found = iso.ISO.GetDirectoryNames("Logs/*.*");
foreach (string s in found)
{
// do some time consuming processing here
}
}
}


First I attempted to create an Action delegate for the above, and then tried to do this:


Action b = this.PopulateIsolatedStorageList;
Observable.FromAsyncPattern(b.BeginInvoke, b.EndInvoke )().
ObserveOn(Scheduler.ThreadPool).Subscribe();



This did not work.  First, PopulateIsolatedStorageList ended up with a null this pointer.


Secondly, it seemed to run on the main thread in any case.





A bit of lateral thinking required


What are my goals?



  1. I want to run my action on a worker thread.

  2. I want to perform some completed action on the UI thread (namely OnPropertyChanged).

Why not create an enumeration of things I want to get done on the worker thread then?


Action[] a = { PopulateIsolatedStorageList};
a.ToObservable(Scheduler.ThreadPool).Subscribe
( action => action(),
      () => Deployment.Current.Dispatcher.BeginInvoke(() => UINotify() ));


Where UINotify() is the expression to perform on the main thread.

 

And surprisingly, it all works.

Update – It helps if you find the right method


Having searched some more I found another mechanism, which removes the need to create the array, and is probably the proper way to do it.


Observable.ToAsync(PopulateIsolatedStorageList)()
.Subscribe(
     _ => { },
() => Deployment.Current.Dispatcher.BeginInvoke(() => UINotify() ));


No comments:

Post a Comment