简体   繁体   English

MVVM Light注入带参数的DataService

[英]MVVM Light inject DataService with parameter

My ExampleViewModel has a parameter (a model) that it needs to function properly. 我的ExampleViewModel有一个参数(一个模型),它需要正常运行。 I also have a list variant of the ExampleViewModel that just contains a ObservableCollection<ExampleViewModel> and has some wrapper methods. 我也有ExampleViewModel的列表变体,它仅包含一个ObservableCollection<ExampleViewModel>并具有一些包装方法。

The issue shows it self when I try to use dependency injection with MVVM Light. 当我尝试在MVVM Light中使用依赖项注入时,该问题表明它是自我的。 Let me explain the scenario with some code. 让我用一些代码解释这种情况。

default ViewModelLocator: 默认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() {}
}

Simple MainViewModel: 简单的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;
    }
}

And the ListMainViewModel fills it's list like this: 然后ListMainViewModel像这样填充它的列表:

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

Because of the list creation in the ListMainViewModel I can't inject the data source in the constructor and have to use it as shown under // Used now . 由于在ListMainViewModel中创建了列表,我无法将数据源注入构造器中,而必须如// Used now使用下所示使用它。 Which is fine, but when I try to unit test problems occur, as you can probably imagine. 很好,但是当我尝试进行单元测试时,可能会出现问题。

I use a unit test like this at the moment: 我现在使用这样的单元测试:

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));
}

Note: Not sure if the unit test is correct. 注意:不确定单元测试是否正确。 But the problem occurs while creating the SelectedMainViewModel because it doesn't fetch a DataService . 但是在创建SelectedMainViewModel时会发生问题,因为它没有获取DataService

For now I have two choices (I think), I can make the MainModel in MainViewModel optional, which is not something that should be possible and contructor inject the IDataService. 现在,我有两个选择(我认为),我可以将MainViewModel中的MainModel设置为可选,这是不可能的,构造函数可以注入IDataService。 Or I can discover a way to make the _service find-able by the MainViewModel. 或者,我可以找到一种使MainViewModel可找到_service的方法。

Is there any elegant way to solve this? 有什么优雅的方法可以解决这个问题吗? Because I have the feeling I have to make some hack using if (InDesignMode) or something similar. 因为我有种感觉,我必须使用if (InDesignMode)或类似的东西进行一些修改。

You mention that: 您提到:

I can't inject the data source in the constructor and have to use it as shown under // Used now . 我不能将数据源注入构造函数中,而必须按// Used now使用下所示使用它。

What are you seeing when you try this? 尝试此操作时会看到什么? What exception is thrown? 抛出什么异常? Why doesn't the below work? 为什么下面的方法不起作用?

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

I think it may help if you get away from using a service locator, which looks to be an anti-pattern for your goal. 我认为,如果您不使用服务定位器可能会有所帮助,这似乎是您目标的反模式。 When using a DI container, it's best to create the entire object graph at the application start or web request (for web apps). 使用DI容器时,最好在应用程序启动或Web请求(对于Web应用程序)时创建整个对象图。 But here you are using the new keyword to create your MainViewModel. 但是,这里您使用new关键字创建MainViewModel。

See this post . 看到这篇文章

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM