I've got a simple little winforms app that performs a long running process on another thread via a TPL Task. During this long running process I'd like to update the UI (the progress bar or something). Is there a way to do this without being required to .ContinueWith()?
public partial class Form1 : Form
{
private Task _childTask;
public Form1()
{
InitializeComponent();
Task.Factory.StartNew(() =>
{
// Do some work
Thread.Sleep(1000);
// Update the UI
_childTask.Start();
// Do more work
Thread.Sleep(1000);
});
_childTask = new Task((antecedent) =>
{
Thread.Sleep(2000);
textBox1.Text = "From child task";
}, TaskScheduler.FromCurrentSynchronizationContext());
}
}
Executing this code I get the ubiquitous exception:
Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on.
You're passing the
TaskScheduler
asstate
(orantecedent
, as you called it). That doesn't make much sense.I'm not sure what exactly do you want to do, but you need to specify the
TaskScheduler
when you're starting theTask
, not when you're creating it. Also, it seems thatchildTask
doesn't have to be a field:Of course, all this is going to be much easier with C# 5 and
await
:You can't make
async
constructor, but you can run anasync
method from it. “Doing work” doesn't run on the UI thread, because it was started explicitly throughTask.Run()
. But sinceStartAsync()
was called directly, it executes on the UI thread.Yes, you can explicitly call
BeginInvoke
on the Window/Control that you want to communicate with. In your case this would look like this: