MVVMLight和平台特定的服务实现

时间:2015-05-25 21:37:28

标签: c# mvvm-light

我拥有什么

使用MVVMLight,我有一些在便携式项目中声明的服务接口以及Windows Phone项目(WP8.1 SL)中的相应实现。要注册实现,我在SimpleIoc.Default.Register类中的Application_Launching方法中使用App

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不会收到消息(因为还没有该虚拟机的实例)。 / p>

可能的解决方案是在注册视图模型时使用true作为参数。

SimpleIoc.Default.Register<TagColorViewModel>(true);

遗憾的是,这并不奏效。原因是,从上面的构造函数中可以看出,TagColorViewModel依赖于INavigationService。这反过来在Application_Launching方法中注册,该方法在调用视图模型定位器的静态构造函数之后。结果是SimpleIoc无法创建TagColorViewModel的实例,因为没有已知的INavigationService接口或实现。

实际问题

我该如何解决这个问题?换句话说:如何在MVVMLights 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 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

结合使用Xamarin的Dependency Service和MVVMLight。 MVVMLight的Register方法有一个重载,您可以编写自己的函数来生成实例。

将所有服务注册重新放回ViewModelLocator,如下所示:

SimpleIoc.Default.Register<Service.INavigationService>(() => {
     return DependencyService.Get<Service.INavigationService>();
});

然后将适当的程序集属性放在特定于平台的服务实现上......

[assembly: Xamarin.Forms.Dependency(typeof(NavigationService))]
相关问题