We're building a wpf application. We have pretty loading indicators. I noticed they "lag" sometimes a while ago, but it wasn't a huge deal. We make heavy use of the async await keywords to keep the application responsive during heavy work.
We had some performance problem which caused me to look deeper into how async await, the UI-Thread and the application freezing connect.
The way I understand it, mainly based on this post If async-await doesn't create any additional threads, then how does it make applications responsive?, is that my loading indicator can only spin, while no other code is being executed on the UI Thread. Trivial code will execute fast enough that you don't see any "lag".
I thought I had found the problem. We thought async await was a magic pattern that prevents the UI from freezing.
To fix it, I need to move the blocking code into actual background threads. But I cannot do that, because most of that code has to do with accessing either UI elements like Windows
or UserControls
or accessing the Binding
properties, all of which cannot be manipulated from outside the UI-Thread.
I can only create Windows
on the UI-Thread. So how would I do something as simple as showing a responsive splash screen?
var splashScreen = new SplashScreen();
splashScreen.Show();
var startUpWindow = new StartUpWindow(); // lets say this always takes 2 seconds
startUpWindow.Show(); // lets say this always takes 1 second
I cannot get around doing this on the UI Thread as far as i can tell. Any amount of trickery via async await, or Task.Run into Dispatcher.Invoke will always end up executing this code on the UI-Thread which will in turn always freeze my application.
This seems like a pretty big oversight to me. Too big to exist. How can a UI framework freeze every time I open a new Window or add a new control or am forced to use the UI-Thread for any other reason? Am I missing something?
Edit: Yes background threads stop the freezing. Also my application is probably not perfect. The point is, you cannot create/show windows on background threads. You cannot access ObservableCollections on background threads.
Try fixing my 4 line code example. Its not a complex or contrived example. The way I see it currently its unsolvable.