I am trying to understand how to update a UI from an event while using async/await pattern. Below is the test code I am using on a WinForm app. I am not even sure this is the right way to go about it. What is necessary to allow the pwe_StatusUpdate method to update the UI? The cross-thread operation error is thrown there.
Thanks for reading.
// calling code
ProcessWithEvents pwe = new ProcessWithEvents();
pwe.StatusUpdate += pwe_StatusUpdate;
await pwe.Run();
void pwe_StatusUpdate(string updateMsg)
{
// Error Here: Cross-thread operation not valid: Control '_listBox_Output' accessed from a thread other than the thread it was created on.
_listBox_Output.Items.Add(updateMsg);
}
-
// Class with long running process and event
public delegate void StatusUpdateHandler(string updateMsg);
public class ProcessWithEvents
{
public event StatusUpdateHandler StatusUpdate;
public async Task Run()
{
await Task.Run(() =>
{
for (int i = 0; i < 10; i++)
{
RaiseUpdateEvent(String.Format("Update {0}", i));
Thread.Sleep(500);
}
});
}
private void RaiseUpdateEvent(string msg)
{
if (StatusUpdate != null)
StatusUpdate(msg);
}
}
-
//Just declare a delegate like so
//Then declare the delegate method like so:
//Now just call the delegate:
You should use
Invoke
method ofControl
. It executes some code in Control's thread. Also you can checkInvokeRequired
property to check if you need to callInvoke
method (it checks if the caller is on a different thread than the one the control was created on).Simple example:
In some cases you should check the
IsHandleCreated
property ofControl
before callingInvoke
method. IfIsHandleCreated
returns false then you need wait while Control's handle will be createdThe
async
pattern has support for progress updates.In short, your
async
method can take anIProgress<T>
, and your calling code passes in an implementation of that interface (usuallyProgress<T>
).Here is another example