I have an MVVM Cross application running on Windows Phone 8 which I recently ported across to using Portable Class Libraries.
The view models are within the portable class library and one of them exposes a property which enables and disables a PerformanceProgressBar from the Silverlight for WP toolkit through data binding.
When the user presses a button a RelayCommand kicks off a background process which sets the property to true which should enable the progress bar and does the background processing.
Before I ported it to a PCL I was able to invoke the change from the UI thread to ensure the progress bar got enabled, but the Dispatcher object isn't available in a PCL. How can I work around this?
Thanks
Dan
Another option that could be easier is to store a reference to SynchronizationContext.Current in your class's constructor. Then, later on, you can use _context.Post(() => ...) to invoke on the context -- which is the UI thread in WPF/WinRT/SL.
All the MvvmCross platforms require that UI-actions get marshalled back on to the UI Thread/Apartment - but each platform does this differently....
To work around this, MvvmCross provides a cross-platform way to do this - using an
IMvxViewDispatcherProvider
injected object.For example, on WindowsPhone
IMvxViewDispatcherProvider
is provided ultimately byMvxMainThreadDispatcher
in https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross.WindowsPhone/Views/MvxMainThreadDispatcher.csThis implements the
InvokeOnMainThread
using:For code in ViewModels:
ViewModel
inherits fromMvxViewModel
MvxViewModel
inherits from anMvxApplicationObject
MvxApplicationObject
inherits from anMvxNotifyPropertyChanged
MvxNotifyPropertyChanged
object inherits from anMvxMainThreadDispatchingObject
MvxMainThreadDispatchingObject
is https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross/ViewModels/MvxMainThreadDispatchingObject.csSo... your ViewModel can just call
InvokeOnMainThread(() => DoStuff());
One further point to note is that MvvmCross automatically does UI thread conversions for property updates which are signalled in a
MvxViewModel
(or indeed in anyMvxNotifyPropertyChanged
object) through theRaisePropertyChanged()
methods - see:in https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross/ViewModels/MvxNotifyPropertyChanged.cs
This automatic marshalling of
RaisePropertyChanged()
calls works well for most situations, but can be a bit inefficient if you Raise a lot of changed properties from a background thread - it can lead to a lot of thread context switching. It's not something you need to be aware of in most of your code - but if you ever do find it is a problem, then it can help to change code like:to:
If you ever use
ObservableCollection
, then please note that MvvmCross does not do any thread marshalling for theINotifyPropertyChanged
orINotifyCollectionChanged
events fired by these classes - so it's up to you as a developer to marshall these changes.The reason:
ObservableCollection
exists in the MS and Mono code bases - so there is no easy way that MvvmCross can change these existing implementations.If you don't have access to the Dispatcher, you can just pass a delegate of the BeginInvoke method to your class:
Then to instanciate it (from a class that has access to the dispatcher):
Or you can also create a wrapper around your dispatcher.
First, define a IDispatcher interface in your portable class library:
Then, in the project who has access to the dispatcher, implement the interface:
Then you can just pass this object as a IDispatcher instance to your portable class library.