我的拥有
使用MVVMLight,我拥有一些服务接口,在一个可移植项目中声明,并在Windows Phone项目(WP8.1 SL)中有相应的实现。要注册这些实现,我在App
类的Application_Launching
方法中使用SimpleIoc.Default.Register
。
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);
...
}
...
}
视图模型定位器位于可移植项目中,并在静态构造函数中向IOC容器注册所有视图模型,就像文档中所说的那样。
static ViewModelLocator()
{
...
SimpleIoc.Default.Register<TagColorViewModel>();
...
}
TagColorViewModel
是这些模型之一。在相应的视图显示之前,它会接收一条消息。例如,当单击标签以更改其颜色时使用MessengerInstance.Send
,然后使用导航服务导航到标签颜色更改视图。
// TagViewModel
private void ChangeColor()
{
MessengerInstance.Send(Tag, TagColorViewModel.MessengerToken.SetTag);
_navigationService.Navigate("/UI/Tagging/TagColor.xaml");
}
此消息接收器在构造函数中注册。
// TagColorViewModel
[PreferredConstructor]
public TagColorViewModel(INavigationService navigationService)
{
...
// Messages
MessengerInstance.Register<Tag>(this, MessengerToken.SetTag, SetTag);
}
实际问题
由于MVVMLight中的视图模型是在其对应的视图上第一次使用之前创建的,因此消息不会被TagColorViewModel
接收到(仅仅是因为该VM的实例还不存在)。
一种可能的解决方案是在注册视图模型时使用true
作为参数。
SimpleIoc.Default.Register<TagColorViewModel>(true);
很遗憾,此方法不可用。原因在于如上面的构造函数所示,
TagColorViewModel
依赖于 INavigationService
,而该服务是在 Application_Launching
方法中注册的,该方法在视图模型定位器的静态构造函数被调用之后执行。结果是 SimpleIoc 无法创建 TagColorViewModel
的实例,因为没有已知的 INavigationService
接口或实现。
实际问题
我该如何解决这个问题?换句话说,我该如何在 MVVMLight 的 SimpleIoc 中注册特定于平台的服务,以使其能够在注册视图模型期间创建它们的实例?
Xamarin 似乎使用装饰器来解决这些问题,但我不知道 MVVMLight 中是否有类似的结构。
Xamarin.Forms.Dependency(typeof(PopupService))
当前解决方法
我的当前解决方法是在所有特定于平台的服务注册之后立即获取一个永远不会再使用的实例。虽然这个方法有效,但我并不认为这是正确的解决方案。
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>();
...
}