Reputation: 2029
Using MVVMLight, I have some service interfaces that are declared in a portable project and the corresponding implementations in a Windows Phone project (WP8.1 SL). To register the implementations I use SimpleIoc.Default.Register
in the Application_Launching
method within the App
class.
public partial class App : Application
{
...
private async void Application_Launching(object sender, LaunchingEventArgs e)
{
...
// add some platform specific services to the IOC container
SimpleIoc.Default.Register<INavigationService, NavigationServiceWP>(true);
SimpleIoc.Default.Register<ISettingsService, SettingsService>(true);
SimpleIoc.Default.Register<IThemeService, ThemeService>(true);
SimpleIoc.Default.Register<IGeofenceService, GeofenceService>(true);
SimpleIoc.Default.Register<IVersionService, TrialInformation>(true);
SimpleIoc.Default.Register<IPhoneService, PhoneServices>(true);
...
}
...
}
The view model locator is located in the portable project and registers all view models to the IOC container in a static constructor, just as the docs say.
static ViewModelLocator()
{
...
SimpleIoc.Default.Register<TagColorViewModel>();
...
}
The TagColorViewModel
is one of these models. It receives a message before the corresponding view is shown. For example, when a tag is clicked to change its color then MessengerInstance.Send
is used, and afterwards the navigation service is used to navigate to the tag color change view.
// TagViewModel
private void ChangeColor()
{
MessengerInstance.Send(Tag, TagColorViewModel.MessengerToken.SetTag);
_navigationService.Navigate("/UI/Tagging/TagColor.xaml");
}
This message receiver is registered in the constructor.
// TagColorViewModel
[PreferredConstructor]
public TagColorViewModel(INavigationService navigationService)
{
...
// Messages
MessengerInstance.Register<Tag>(this, MessengerToken.SetTag, SetTag);
}
Because the view model is created in MVVMLight right before it is used for the first time via its corresponding view, the message is not received by TagColorViewModel
(simply because there is no instance of that VM yet).
A possible solution would be to use true
as parameter when registering the view model.
SimpleIoc.Default.Register<TagColorViewModel>(true);
This unfortunately doesn't work. The reason is that, as can be seen in the constructor above, TagColorViewModel
has a dependency to the INavigationService
. This in turn is registered in the Application_Launching
method, which is after the static constructor of the view model locator is called. The result is that SimpleIoc can't create an instance of TagColorViewModel
because there is no known INavigationService
interface or implementation.
How can I solve this issue? In other words: How can I register platform specific services in MVVMLights SimpleIoc so that I can let it create instances of view models during their registration?
Xamarin seems to use a decorator to solve such issues but I don't know of any comparable construct in MVVMLight.
Xamarin.Forms.Dependency(typeof(PopupService))
My current workaround is to get an instance that is never used later right after all the platform specific services are registered. It works but I don't think this is the correct solution to that.
private async void Application_Launching(object sender, LaunchingEventArgs e)
{
...
// add some platform specific services to the IOC container
SimpleIoc.Default.Register<INavigationService, NavigationServiceWP>(true);
...
var tcvm = SimpleIoc.Default.GetInstance<TagColorViewModel>();
...
}
Upvotes: 6
Views: 571
Reputation: 931
Use a combination of Xamarin's Dependency Service and MVVMLight. MVVMLight's Register method has an overload where you can write your own function to generate the instance.
Put all of your Service Registrations back into ViewModelLocator like this:
SimpleIoc.Default.Register<Service.INavigationService>(() => {
return DependencyService.Get<Service.INavigationService>();
});
Then go and put the appropriate assembly attributes on your platform-specific implementation of the services...
[assembly: Xamarin.Forms.Dependency(typeof(NavigationService))]
Upvotes: 1
Reputation: 1393
One approach might be to perform the platform-specific service registrations during the App construction rather than in Application_Launching
. That would ensure that all your services are registered as early as possible. The only caveat would be to make sure they happen after the call to ServiceLocator.SetLocatorProvider
.
Upvotes: 0