FromCurrentSynchronizationContext, am I missing something?

c#, task-parallel-library, tpl-dataflow, user-interface

Solution

The reason your UI is blocked is becase you're using `FromCurrentSynchronizationContext`. It causes the code to run on the UI thread, which means it will freeze if you're doing some long running action (most likely `GetFileFromLargeFile()`).

On the other hand, you have to run the `lblProgress.Text` on the UI thread.

I'm not sure you should set `lblProgress.Text` directly in this code, it look like too tight coupling to me. But if you want to do that, I think you should run just that line on the UI thread:

var producer = new ActionBlock<someObject>(async largeFile =>
{
    var file = GetFileFromLargeFile(largeFile);
    if (file != null)
    {
        TotalFound++;
        await buffer.SendAsync(file);
        await Task.Factory.StartNew(
            () => lblProgress.Text = String.Format("{0}", TotalFound),
            CancellationToken.None, TaskCreationOptions.None, uiScheduler);
    }
});

But even better solution would be if you made `GetFileFromLargeFile()` asynchronous and made sure it doesn't do any long-running actions on the UI thread (`ConfigureAwait(false)` can help you with that). If you did that, the code of the `ActionBlock` could run on the UI thread without freezing your UI:

var producer = new ActionBlock<someObject>(async largeFile =>
{
    var file = await GetFileFromLargeFile(largeFile);
    if (file != null)
    {
        TotalFound++;
        await buffer.SendAsync(file);
        lblProgress.Text = String.Format("{0}", TotalFound)
    }
}, options);

Problem

I current working an application that reads from a large binary file, which holds several thousands files, every file is being processed by some other class in application. This class returns either an object or null. I want to show a progress on the main form but for some reason I can't get my head around it. ``` int TotalFound = 0; var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext; BufferBlock<file> buffer = new BufferBlock<file>(); DataflowBlockOptions options = new DataflowBlockOptions(){ TaskScheduler = uiScheduler, }; var producer = new ActionBlock<someObject>(largeFile=>{ var file = GetFileFromLargeFile(largeFile); if(file !=null){ TotalFound++; buffer.post(file); lblProgress.Text = String.Format("{0}", TotalFound); } }, options); ``` The above code freezes my Form, even do I use "TaskScheduler.FromCurrentSynchronizationContext", why? Because when I use the code below my form updates fine ``` DataflowBlockOptions options = new DataflowBlockOptions(){ TaskScheduler = uiScheduler, }; var producer = new ActionBlock<someObject>(largeFile=>{ var file = GetFileFromLargeFile(largeFile); if(file !=null){ Task.Factory.StartNew(() => { TotalFound++; buffer.Post(file); }).ContinueWith(uiTask => { lblProgress.Text = String.Format("{0}", TotalFound); },CancellationToken.None, TaskContinuationOptions.None, uiScheduler); } }); ``` I am new to this whole TPL Dataflow, so I am hoping someone could share some light on why in the second code snippet it works and in the first snippet it doesn't. Kind regards, Martijn

Original source