See the question and my original answer on StackOverflow

.NET has the concept of SynchronizationContext:

Provides the basic functionality for propagating a synchronization context in various synchronization models.

This context's main method is named Post and it basically dispatches an asynchronous message to the context. This is where, depending on the underlying UI technology (Winforms, WPF, etc.), or non UI technology, things can be tweaked and gracefully work with the constraints these technology has.

By default, the Tasks' task scheduler does not use the current synchronization context, but instead uses the ThreadPool which you cannot really control (and does not play with Winforms, nor WPF by the way), so you have to specify you want the TaskScheduler from the SynchronizationContext, which you only partially did.

Since you're running a Winforms app, the current synchronization context (Synchronization.Current) should be of WindowsFormsSynchronizationContext type. If you can have a look at its implementation of Post, you will see this:

public override void Post(SendOrPostCallback callback, object state)
    if (controlToSendTo != null)
        controlToSendTo.BeginInvoke(callback, new object[] { state });

This context's implementation should work fine with Winforms UI thread ... provided you use it. In fact you almost got it right, you just forgot to use it in the StartNew method.

So, just change your code into this:

Task.Factory.StartNew(a, fPath,
    CancellationToken.None, TaskCreationOptions.None, // unfortunately, there is no easier overload with just the context...
        t => { dataGridView2.DataSource = t.Result; },

And it should work.