Mou Mou - 1 month ago 17
C# Question

My UI getting updated when all task done

see my below code and tell me what is wrong there for which my UI is getting updated when all task finish but as per code it suppose to update label value when my routine is calling by task. what to change in my code.

say for example when DoSomething1 is getting called then label3 need to be updated and reflected before user.

private void button1_Click(object sender, EventArgs e)
{
TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
var token = Task.Factory.CancellationToken;

var tasks = new[]
{
Task.Factory.StartNew( DoSomething1,token,TaskCreationOptions.None, uiScheduler),
Task.Factory.StartNew(DoSomething2,token,TaskCreationOptions.None, uiScheduler),
Task.Factory.StartNew(DoSomething3,token,TaskCreationOptions.None, uiScheduler)
};
Task.WaitAll(tasks);
//var things = Task.WhenAll(tasks);

int x=0;
}

public void DoSomething1()
{
//this.label3.BeginInvoke(new Action(() =>
//{
// this.label3.Text = "DoSomething1 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId;
//}));
this.label3.Text = "DoSomething1 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId;
System.Threading.Thread.Sleep(1000);
}

public void DoSomething2()
{
//this.label4.BeginInvoke(new Action(() =>
//{
// this.label4.Text = "DoSomething2 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId;
//}));
this.label4.Text = "DoSomething2 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId;
System.Threading.Thread.Sleep(1000);
}

public void DoSomething3()
{
//this.label5.BeginInvoke(new Action(() =>
//{
// this.label5.Text = "DoSomething3 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId;
//}));
this.label5.Text = "DoSomething3 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId;
System.Threading.Thread.Sleep(1000);
}

Answer

The other answer is correct, as far as it goes. Using FromCurrentSynchronizationContext() causes the scheduler that's being used to be one that always uses the current thread to run tasks. I.e. the UI thread. The tasks should be run with Task.Run() and without a specific scheduler (it will default to the thread pool scheduler). BeginInvoke() is one option for correctly accessing the Label objects.

However, it seems to me it would be better to fix all of the code so that it's more idiomatic in the current async/await paradigm. For example:

private async void button1_Click(object sender, EventArgs e)
{
    TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
    var token = Task.Factory.CancellationToken;

    var tasks = new[]
    {
        DoSomething1(),
        DoSomething2(),
        DoSomething3()
    };
    await Task.WhenAll(tasks);

    int x=0;
}

public async Task void DoSomething1()
{
    this.label3.Text = "DoSomething1 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId;
    // replace with `Task.Run()` or whatever already-asynchronous
    // operation you need/want. Likewise in the other methods.
    // Don't forget to pass the CancellationToken to these methods,
    // and then on to whatever tasks you actually are running.
    await Task.Delay(1000);
}

public async Task DoSomething2()
{
    this.label4.Text = "DoSomething2 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId;
    await Task.Delay(1000);
}

public async Task DoSomething3()
{
    this.label5.Text = "DoSomething3 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId;
    await Task.Delay(1000);
}