I'm building a WPF application. I'm doing some async communication with the server side, and I use event aggregation with Prism on the client. Both these things results in new threads to be spawned which are not the UI thread. If I attempt to do "WPF operations" on these callback and event handler threads the world will fall apart, which it now has started doing.
First I met problems trying to create some WPF objects in the callback from server. I was told that the thread needed to run in STA mode. Now I'm trying to update some UI data in a Prism event handler, and I'm told that:
The caller cannot access this thread because a different thread owns it.
So; what's the key to getting things right in WPF? I've read up on the WPF Dispatcher in this MSDN post. I'm starting to get it, but I'm no wizard yet.
Anyone wanna clearify things for me? Any related recommendations, etc? Thanks!
The UI thread queues work items inside an object called a Dispatcher. The Dispatcher selects work items on a priority basis and runs each one to completion. Every UI thread must have at least one Dispatcher, and each Dispatcher can execute work items in exactly one thread.
WPF supports a single-threaded apartment model that has the following rules: One thread runs in the entire application and owns all the WPF objects. WPF elements have thread affinity, in other words other threads can't interact with each other.
A dispatcher is often used to invoke calls on another thread. An example would be if you have a background thread working, and you need to update the UI thread, you would need a dispatcher to do it. Follow this answer to receive notifications.
WPF requires that most of its objects be tied to the UI thread. This is known as thread affinity, meaning you can only use a WPF object on the thread on which it was created.
Going over each of your questions, one by one:
Invoke
everything. The key is to only invoke onto the UI thread if necessary. To do this, you can use the Dispatcher.CheckAccess method.Invoke
if necessary. That being said, at some points it is unavoidable, so no, I would not say it is bad practice at all. It is just one solution to a problem that you will encounter every now and then.Dispatcher.CurrentDispatcher
. For complex scenarios, this may not be sufficient, but I (personally) have not seen them.Dispatcher
can be used to gain access to the UI thread for the application. But it is not in and of itself the UI thread.BackgroundWorker
is generally used when you have a time-consuming operation and want to maintain a responsive UI while running that operation in the background. Normally you do not use BackgroundWorker instead of Invoke, rather, you use BackgroundWorker in conjunction with Invoke. That is, if you need to update some UI object in your BackgroundWorker, you can Invoke onto the UI thread, perform the update, and then return to the original operation.There's a lot to be said about BackgroundWorker
, I'm sure many questions are already devoted to it, so I won't go into too much depth. If you're curious, check out the MSDN page for BackgroundWorker class.
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