Oh man, I’ve been fighting with this for many days now. I mostly have a solution so I wanted to write it down. Here is the problem:
As a rule, everything in Windows Phone and Win8 modern UI is asynchronous. That means almost everything runs in a different thread.
As a rule, you can’t update the UI if you aren’t running in the UI thread. You have to “invoke” your code via a Dispatcher to go run the code in the UI thread.
Well, what if you wanted to put most of your code in a Portable Class Library (PCL) so that you could re-use it? How would you have a design that is generic enough to use across multiple platforms, but yet have enough flexibility to take advantage of the device-specific features? Here is one way to do this:
For example, if you had an application which works with a Compass on the current device, you might approach it like this:
- Have ICompassProvider defined in the PCL
- Have a WP8CompassProvider, which uses the Windows Phone compass and implements ICompassProvider, in the WP8 class library
- Have the ViewModel constructor in the UI “inject” the WP8CompassProvider. Presumably, that ViewModel has an argument of-type ICompassProvider
This seems like a pretty good approach. There is good segregation and management of the dependencies, and the app pretty much works as expected.
One thing I stumbled on though was the matter of threading. Now, using the picture above, imagine that the WP8CompassProvider (in the WP8 class library) generates an event in another thread, which triggers a PropertyChanged event up in the PCL, which is then received by the WP8 UI. Well, you get an illegal-cross-thread exception if you do that.
Worse, in the WP8 Class Library, you can’t use Dispatcher, because there is no application context. I found some interesting articles on using SynchronizationContext and/or TaskScheduler, but both of those didn’t work because it reported a null context.
So, how I addressed this was to simply pass in the Dispatcher to the constructor of the WP8CompassProvider class. Again, this is done in the WP8 UI constructor when the DataContext is set.
This is good because all of the dependencies which are needed for the entire functionality, are all injected in that one place. You could of-course use some dependency injection framework, but since these are all injectable in the constructor – that means these classes are already very unit-test-friendly!
So bottom line, if you have dependencies in a project which uses a PCL, see how many of those dependencies you can manage by injecting them into the constructor of the ViewModel, from the UI.