Reputation: 169
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
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