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); } }
-
Using async/await relies on suspending functions, instead of blocking threads, which provides clean code, without the risk of blocking the user interface.
You can start an async operation from the UI thread, await it without blocking the UI thread, and naturally resume on the UI thread when it's done.
@pm100 The method they're calling is an asyncrhonous method that interacts with the UI, and as such needs to be run on the UI thread. It's incorrect to run it in a non-UI thread. It will never work if you do that. It needs to be run in the UI thread.
The differences between asynchronous and synchronous include: Async is multi-thread, which means operations or programs can run in parallel. Sync is single-thread, so only one operation or program will run at a time. Async is non-blocking, which means it will send multiple requests to a server.
The async
pattern has support for progress updates.
In short, your async
method can take an IProgress<T>
, and your calling code passes in an implementation of that interface (usually Progress<T>
).
public class ProcessWithUpdates { public async Task Run(IProgress<string> progress) { await Task.Run(() => { for (int i = 0; i < 10; i++) { if (progress != null) progress.Report(String.Format("Update {0}", i)); Thread.Sleep(500); } }); } } // calling code ProcessWithUpdates pwp = new ProcessWithUpdates(); await pwp.Run(new Progress<string>(pwp_StatusUpdate));
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