MVVM Light使用参数注入DataService

时间:2014-12-21 11:45:33

标签: c# dependency-injection moq mvvm-light

我的ExampleViewModel有一个需要正常运行的参数(模型)。我还有ExampleViewModel的列表变体,它只包含ObservableCollection<ExampleViewModel>并且有一些包装器方法。

当我尝试使用依赖注入MVVM Light时,问题显示出来了。让我用一些代码来解释这个场景。

默认ViewModelLocator:

public class ViewModelLocator {

    public ViewModelLocator() {
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

        if (ViewModelBase.IsInDesignModeStatic) {
            SimpleIoc.Default.Register<IDataService, DesignDataService>();
        } else {
            SimpleIoc.Default.Register<IDataService, DataService>();
        }

        SimpleIoc.Default.Register<MainViewModel>();
    }

    public MainViewModel Main {
        get {
            return ServiceLocator.Current.GetInstance<MainViewModel>();
        }
    }

    public static void Cleanup() {}
}

简单的MainViewModel:

public class MainViewModel : ViewModelBase {

    private IDataService _service;
    private MainModel _model;

    // Goal. I think?
    public MainViewModel(IDataService service, MainModel model) {
        _service = service;
        _model = model;
    }

    // Used now
    public MainViewModel(MainModel model) {
        _service = ServiceLocator.Current.GetInstance<IDataService>();
        _model = model;
    }
}

ListMainViewModel填充它的列表如下:

Mains = new ObservableCollection<MainViewModel>(
    _service.GetAll().Select(model => new MainViewModel(model))
);

由于ListMainViewModel中的列表创建,我无法在构造函数中注入数据源,必须按// Used now下所示使用它。哪个好,但是当我尝试单元测试问题时,你可以想象。

我现在使用这样的单元测试:

public void ListMainViewModel_DoSomething_Success() {

    // Arrange
    var mock = new Mock<IDataService>();
    mock.Setup(m => m.Create(new MainModel { Naam = "Create" }));
    mock.Setup(m => m.Update(new MainModel { Naam = "Update" }));

    var listMainViewModel = new ListMainViewModel(mock.Object);

    var selected = new MainModel() { Prop = "Test" };

    listMainViewModel.SelectedMainViewModel = new MainViewModel(selected);

    // Act
    listMainViewModel.DoSomething();

    // Assert
    mock.Verify(x => listMainViewModel.DoSomething(), Times.Exactly(1));
}

注意:不确定单元测试是否正确。但是在创建SelectedMainViewModel时会出现问题,因为它无法获取DataService

现在我有两个选择(我认为),我可以使MainViewModel中的MainModel可选,这不应该是可能的,并且构造函数注入IDataService。或者我可以通过MainViewModel找到一种使_service可以找到的方法。

有没有优雅的方法来解决这个问题?因为我觉得我必须使用if (InDesignMode)或类似的东西进行一些黑客攻击。

1 个答案:

答案 0 :(得分:1)

你提到:

  

我无法在构造函数中注入数据源,必须按// Used now下所示使用它。

当你尝试这个时,你看到了什么?抛出什么异常?为什么以下工作没有?

Mains = new ObservableCollection<MainViewModel>(
    _service.GetAll().Select(model => new MainViewModel(model, _service))
);

我认为如果你不再使用服务定位器可能会有所帮助,这似乎是你的目标的反模式。使用DI容器时,最好在应用程序启动或Web请求(对于Web应用程序)创建整个对象图。但是在这里您使用new关键字来创建MainViewModel。

请参阅此post