How can SynchronizationContext.Current of the main thread become null in a Windows Forms application? How can SynchronizationContext.Current of the main thread become null in a Windows Forms application? wpf wpf

How can SynchronizationContext.Current of the main thread become null in a Windows Forms application?


Sly, I have run into the exact same behavior when a mixture of WPF, WCF, and TPL is used. The Main thread's current SynchronizationContext will become null in a few situations.

var context = SynchronizationContext.Current;// if context is null, an exception of// The current SynchronizationContext may not be used as a TaskScheduler.// will be thrownTaskScheduler.FromCurrentSynchronizationContext();

According to this post on the msdn forums, this is a confirmed bug in the TPL in 4.0. A coworker is running on 4.5 and does not see this behavior.

We solved this by creating a TaskScheduler in a static singleton with the main thread using FromCurrentSynchronizationContext and then always reference that task scheduler when creating continuations. For example

Task task = Task.Factory.StartNew(() =>  {    // something  }).ContinueWith(t =>  {    // ui stuff  }, TheSingleton.Current.UiTaskScheduler);

This avoids the issue in the TPL on .net 4.0.

UpdateIf you have .net 4.5 installed on your development machine, you will not see this issue even if you are targeting the 4.0 framework. Your users who only have 4.0 installed will still be affected.


Not sure if this is the preferred method but here is how I use the SynchronizationContext:

In you constructor (main thread) save a copy of the current context, that way you are guaranteed(??) to have the right context later no matter what thread you are on.

_uiCtx = SynchronizationContext.Current;

And later in your Task use it to do interact with the main UI thread

_uiCtx.Post( ( o ) =>{ //UI Stuff goes here}, null );


I've created a class for this. It looks like this:

public class UIContext{    private static TaskScheduler m_Current;    public static TaskScheduler Current    {        get { return m_Current; }        private set { m_Current = value; }    }    public static void Initialize()    {        if (Current != null)            return;        if (SynchronizationContext.Current == null)            SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());        Current = TaskScheduler.FromCurrentSynchronizationContext();    }}

On startup of my App I call UIContext.Initialize()

And when I need it in a task I just put UIContext.Current as TaskScheduler.

Task.Factory.StartNew(() =>{    //Your code here}, CancellationToken.None, TaskCreationOptions.None, UIContext.Current);