user3363744
user3363744

Reputation: 169

Why code after Await does not run on UI thread?

I have used delegates in the past to update the current UI (for example a textbox) with a value that is being processed in my thread. I was under the assumption that async and await took care of this for you.

When I run the code below -when the button is pressed start a new task that will count up to 100 every 100ms. The count should be displayed on the UI, but I get a targetInvocationException instead:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        textBox1.Text = "Press button";
    }

    private async void button1_Click(object sender, EventArgs e)
    {
         await Task1();
    }

    private Task Task1()
    {
        return Task.Factory.StartNew(() => CountMethod());
    }

    private void CountMethod()
    {
        for (int i = 0; i < 100; i++)
        {
            Task.Delay(100).Wait();
            //Console.WriteLine(i.ToString());
            textBox1.Text = i.ToString();
        }
    }
}

Upvotes: 1

Views: 969

Answers (1)

Yacoub Massad
Yacoub Massad

Reputation: 27871

The problem is that you are using a thread-pool thread to access the UI. You are doing this by using the Task.Factory.StartNew method.

Here is how you can fix it:

private async Task Task1()
{
    for (int i = 0; i < 100; i++)
    {
        await Task.Delay(100);

        textBox1.Text = i.ToString();
    }
}

await will capture the current SynchronizationContext so that after the asynchronous wait is complete, the code that follows executes on the UI thread. This is true because await was called by the UI thread (in the case of my example).

In your current code, await is called on a thread-pool thread. In this case the current SynchronizationContext is null and therefore the code that follows the asynchronous wait will be executed also on a thread-pool thread.

Upvotes: 10

Related Questions