MVVMLight和特定平台服务实现

6

我的拥有

使用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>();

    ...
}
2个回答

1
使用Xamarin的Dependency Service和MVVMLight相结合。MVVMLight的Register方法有一个重载,你可以编写自己的函数来生成实例。
将所有的服务注册放回到ViewModelLocator中,像这样:
SimpleIoc.Default.Register<Service.INavigationService>(() => {
     return DependencyService.Get<Service.INavigationService>();
});

然后,请在您特定于平台的服务实现上放置适当的程序集属性...
[assembly: Xamarin.Forms.Dependency(typeof(NavigationService))]

0

一个方法可能是在应用程序构建期间执行特定于平台的服务注册,而不是在 Application_Launching 中执行。这将确保尽早注册所有服务。唯一需要注意的是确保它们发生在对 ServiceLocator.SetLocatorProvider 的调用之后。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接