I am working on a Winform Application. The Method
is started by a BackgroundWorker Thread. I am sorry. I did not mention this earlier.
private void Method()
{
tasks[i] = Task.Factory
.StartNew(() => fileProcessor.ProcessEachMachine(mdetail))
.ContinueWith(UpdateLabel, TaskContinuationOptions.OnlyOnRanToCompletion);
}
I have a long running function ProcessEachMachine
. In the continuation function UpdateLabel
I want to access UIlabel and update the status.
private void UpdateLabel()
{
progressLbl.Text = "updated";
}
But the label is not getting updated. How to access UILabel and update the text of it.?
You have to set the TaskScheduler.FromCurrentSynchronizationContext on ContinueWith or else it will not be run in the UI context. Here is the MSDN on the override that you must use for this call to ContinueWith.
It should end up looking like this:
.ContinueWith(UpdateLabel, null,
TaskContinuationOptions.OnlyOnRanToCompletion,
TaskScheduler.FromCurrentSynchronizationContext());
It may seem like nothing is happening, but the TPL is currently swallowing your cross thread exception. You should probably use the UnobservedTaskException if you are not going to inspect each result or check for its exception. Otherwise, when garbage collection occurs, the exception will happen then...which could create hard to debug errors.
UPDATE
Based on your update about the main Task being setup and started by a Backgroundworker, my main question is why this could not use a Task to start? In fact, if there is not more in the Method
, then this is really just double work and might confuse other developers. You are already started asynchronously, so why not just do your work within the backgroundworker and use an OnComplete method that will UpdateLabel
(as background workers are already context aware).
The main problem is still the same though, so here are some other solutions if you feel you must use the TPL:
Invoke
back onto the main UI thread within the UpdateLabel methodWait
for your original Task to return and then use the worker's oncomplete event to update the label.Here is how I would do this (all pseudo code)
Background Worker Method:
Method() called because of Background worker
private void Method()
{
fileProcessor.ProcessEachMachine(mdetail);
}
Wire up background worker's OnRunWorkerCompleted:
if(!e.Cancelled && !e.Error)
UpdateLabel();
Task only method
Call Method() from the main thread and just let the TPL do its work :)
Task.Factory.StartNew(() => fileProcessor.ProcessEachMachine(mdetail))
.ContinueWith((precedingTask)=>{if(!precedingTask.Error)UpdateLabel;},
null, TaskContinuationOptions.OnlyOnRanToCompletion,
TaskScheduler.FromCurrentSynchronizationContext());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With