0

I have the following bit of code in my Windows 8 Store app:

    public static void ConvertUpdateStreamToCollection<T>(this IObservable<UpdateInfo<T>> input, ObservableCollection<T> list)
    {
        input
            .ObserveOnDispatcher()
            .Subscribe(upInfo => UpdateList(upInfo, list));
    }

That ObserveOnDispatcher is there b.c. this will often be called on a background thread, and when it updates the observable list I will need it to be on the UI dispatcher. To first order this looks like it works fine when I run the app.

But I wish to test this with unit tests. I'm using the built in MSTest. The ObserveOnDispatcher throws, however, complaining there is no valid Window from which to get a CoreDispatcher.

I've seen work arounds for WPF in other places in Stack overflow. But that looks like just something to make the dispatcher run. This error seems more fundamental. Is there a known workaround?

Community
  • 1
  • 1
Gordon
  • 3,012
  • 2
  • 26
  • 35

1 Answers1

3

(edit: better formatting now that I have a keyboard instead of a phone)

There's another way to achieve the same functionality:

.ObserveOnDispatcher() 

Is fairly equivalent to:

.ObserveOn(new DispatcherScheduler(Dispatcher.CurrentDispatcher))

Now, instead of that DispatcherScheduler, have a class like:

public static class Schedulers
{
    public static IScheduler Dispatcher {get; internal set;}    
}

And change usage to:

.ObserveOn(Schedulers.Dispatcher)

Example:

void Main()
{
    // For normal usage, we'll set this to the proper DispatcherScheduler
    Schedulers.Dispatcher = new DispatcherScheduler(Dispatcher.CurrentDispatcher);

    // Do stuff
    new Thingy().DoStuff();

    // for testing usage, we'll set this to be the immediate scheduler
    Schedulers.Dispatcher = Scheduler.Immediate;

    // Do stuff 
    new Thingy().DoStuff();
}

public class Thingy
{
    public void DoStuff()
    {
        var query = Observable.Range(0, 10).ObserveOn(Schedulers.Dispatcher);
        query.Subscribe(Console.WriteLine);
    }
}
JerKimball
  • 16,584
  • 3
  • 43
  • 55
  • Thanks. Your post made me realize I can look at the Rx source code (https://rx.codeplex.com/SourceControl/changeset/view/7881e17c060b#Rx/NET/Source/System.Reactive.Windows.Threading/Reactive/Linq/DispatcherObservable.cs). – Gordon Mar 02 '13 at 09:15
  • One quick question here. You are using the Dispatcher.CurrentDIspatcher... is that going to be the same thing for the whole life of a windows store app? Do you get different ones associated with the "Window" object (where it gets them by default)? – Gordon Mar 02 '13 at 09:16
  • Another solution I thought of was to create a shell ObserveOnMyDispatcher that turned into a null op when running in test mode, and the "official" ObserveOnDispatcher when run in the WD environment, as this would get around any chance of the Dispatcher changing during the running on the WS app... – Gordon Mar 02 '13 at 09:17
  • Dispatcher.CurrentDispatcher is tricky; it's probably better to use Application.Current.Dispatcher. CurrentDispatcher can actually result in the creation of new dispatchers. – JerKimball Mar 02 '13 at 15:07
  • Oh! That is odd. I got that from the source code in Rx! Ok, I'll switch to that, then. Thanks! – Gordon Mar 02 '13 at 20:36
  • CurrentDispatcher will fetch the dispatcher for the currently executing thread - if it doesn't have one (like a background thread), then it'll create one, which is probably not what you'd want here. – JerKimball Mar 02 '13 at 21:29
  • Got it. Looking at Rx code more carefully, what they do is first look for the active window - so that will prevent them from accidentally creating an extra dispatcher. But it may well be useful to create a new dispatcher for an arbitrary thread for some testing... Many thanks for the insight! – Gordon Mar 04 '13 at 08:30