TaskScheduler.FromCurrentSynchronizationContext - how to use WPF dispatcher thread when unit testing TaskScheduler.FromCurrentSynchronizationContext - how to use WPF dispatcher thread when unit testing wpf wpf

TaskScheduler.FromCurrentSynchronizationContext - how to use WPF dispatcher thread when unit testing


It's not exactly easy, but it's not really that hard either. What you need to do is a spin up a worker Thread that's setup as STA and you start up the Dispatcher runtime on it. Once you have that worker sitting there you can dispatch work to it from the unit test threads which are, obviously, not initialized for this kind of work. So, first, here's how you startup the dispatcher thread in your test setup:

this.dispatcherThread = new Thread(() =>{   // This is here just to force the dispatcher infrastructure to be setup on this thread   Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() =>   {       Trace.WriteLine("Dispatcher worker thread started.");   }));   // Run the dispatcher so it starts processing the message loop   Dispatcher.Run();});this.dispatcherThread.SetApartmentState(ApartmentState.STA);this.dispatcherThread.IsBackground = true;this.dispatcherThread.Start();

Now, if you want to cleanly shut that thread down in your test cleanup, which I recommend you do, you simply do the following:

Dispatcher.FromThread(this.dispatcherThread).InvokeShutdown();

So, all that infrastructure stuff out of the way, here's all you need to do in your test to execute on that thread.

public void MyTestMethod{    // Kick the test off on the dispatcher worker thread synchronously which will block until the work is competed    Dispatcher.FromThread(this.dispatcherThread).Invoke(new Action(() =>    {        // FromCurrentSynchronizationContext will now resolve to the dispatcher thread here    }));}


Add this to your test initialisation, to create a context:

SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());


This makes it even simpler

TaskScheduler scheduler = Dispatcher.CurrentDispatcher.Invoke(TaskScheduler.FromCurrentSynchronizationContext)

you code can then use the scheduler explicitly (initialized with TaskScheduler.FromCurrentSynchronizationContext() during runtime)