WPF: Just enough thread to hang yourself
One of the really nice features of WPF is that it comes with a Dispatcher for executing code coming off a thread different from your UI thread. It’s not substantially different from being able to call Invoke() on WinForms controls, but it does have some useful scheduling priority features so that you can schedule actions for just the right point when the UI is doing its thing.
The WPF Dispatcher is used for lots of things, including the IsAsync property in BindingExpression, for when the result of the asynchronous binding finally returns and it needs to set the property value on the control. However you should be very careful what you return from a property that is being bound to the visual object.
When using DataBinding, I ran into a situation where I needed to do some background work to extract an image out of a file. I didn’t want to block the UI so I decided to make the binding asynchronous. Tried it out, and the UI was still blocking; I eventually realized that converters are not performed asynchronously; only the inital property get that you are databound to and a lot of the work was in the converter.
So I refactored the code to do all the work in the property and return an ImageSource, with a nice little ViewModel wrapping my data.
I tried running the App and it died as soon as it extracted the image. It was complaining about an InvalidOperation, I had crossed the streams somewhere. But where?
ImageSources are dispatcher objects, and because I was creating one inside my property which was being executed asyncronusly, it was creating a dispatcher object with a dispatcher not on the UI thread. So, if you’re following a ViewModel pattern and you plan to be doing asyncronus databinding, make sure that all of your UI generation happens in the converters and any background data work happens in the property of your ViewModel.
Perhaps future versions of WPF will allow you to set 2 seperate converters, a Data converter and a UI converter. Where the data converter runs on the background thread, and the results of it feed into the UI Converter if there is one which will execute on the UI thread.