针对分层视图模型的带Unity的MVVM依赖项注入

针对分层视图模型的带Unity的MVVM依赖项注入,mvvm,view,model,dependency-injection,unity-container,Mvvm,View,Model,Dependency Injection,Unity Container,我进行了广泛的搜索,没有找到任何关于如何使用具有多层视图模型的依赖项注入正确设计应用程序的良好指导 如果视图模型需要创建视图模型,而视图模型又需要创建其他视图模型,那么使用Unity之类的工具实现依赖项注入的最佳方法是什么 例如,假设我有一个带有MainViewModel的应用程序,我希望能够在一个选项卡式界面(即Visual Studio)中显示一组不同类型的数据 我执行一个命令,使用名为UsersViewModel的视图模型打开用户对象的集合。此视图模型在其构造函数中采用存储库IUserRe

我进行了广泛的搜索,没有找到任何关于如何使用具有多层视图模型的依赖项注入正确设计应用程序的良好指导

如果视图模型需要创建视图模型,而视图模型又需要创建其他视图模型,那么使用Unity之类的工具实现依赖项注入的最佳方法是什么

例如,假设我有一个带有MainViewModel的应用程序,我希望能够在一个选项卡式界面(即Visual Studio)中显示一组不同类型的数据

我执行一个命令,使用名为UsersViewModel的视图模型打开用户对象的集合。此视图模型在其构造函数中采用存储库IUserRepository。调用IUserRepository上的GetAll方法以获取在视图中网格中显示的用户对象的集合

如果需要编辑特定用户对象的详细信息,我需要创建一个UserViewModel,该模型还需要IUserRepository的实例及其构造函数中特定用户对象的ID。调用IUserRepository上的FindById方法来获取特定的用户对象

我需要在主视图的单独选项卡中显示用户详细信息。我需要能够同时查看/编辑多个用户对象的详细信息,因此我不能仅以模式打开详细信息。因此,UserViewModel需要能够持久化自己的更改,因为UsersViewModel可以在保存特定的UserViewModel之前关闭


那么,在这种情况下,解决UserViewModel实例的最佳方法是什么?我可以将IUnityContainer的一个实例传递到UsersViewModel中,然后用它来解析它们,但从我所读到的内容来看,这是一个坏主意。还有什么办法呢?

我已经用Autofac和MEF设置了一个MVVM应用程序来解决您所说的问题。长话短说,我创建了一个服务接口
IViewModelProvider
,为任意模型提供ViewModels服务。此服务的实现为所有ViewModels提供缓存,如果找不到特定模型所需ViewModel类型的ViewModels,则为模型创建ViewModels

ViewModelProvider
是它自己的IoC容器,它在初始化时反映所有加载的程序集,然后在运行时解析依赖项。ViewModelProvider为服务
IViewModelProvider
注册自身的实例,因此可以将自身传递给
ViewModels
,后者需要实例化新的ViewModels

我对这个解决方案非常满意,因为我觉得这里的关注点很好地分开了。全局ViewModel缓存非常棒,因为它节省了资源,并且您可以实际比较ViewModels是否相等,这是我经常遇到的

这个解决方案可以通过使用与UI相同的IoC容器来简化,正如您在问题中指出的那样。我同意直接将
IUnityContainer
传递给ViewModels不是一个好主意。不过,我看不出使用容器解析ViewModels有任何错误。我建议构建一个简单的服务,它缓存ViewModel实例,并使用
IUnityContainer
创建新的ViewModel

下面的代码是伪代码,混合了一点MEF和一点Autofac语法,但我认为它的内容已经很清楚了:

获取ViewModels的界面:

public interface IViewModelProvider
{
    T GetViewModel<T>(object model);
}
然后,该服务可以注入到您的ViewModels中,ViewModels可以创建自己的子ViewModels,而不必关心这些子ViewModels是否已经存在,因为它们需要创建


希望这有帮助。这是一个广泛的话题,如果您有任何特殊问题,请询问。

我的回答有帮助吗?有更新吗?确实有用。然而,我仍在努力解决项目中的其他无数问题,我也在努力解决这些问题。我还尝试使用存储库,我有一个类似的问题,即如何在较低级别实例化这些存储库。如果你有一个VM A,它创建了VM B,它创建了VM C,那么你的建议就行了。但是,如果它们中的每一个都需要一个新的存储库实例,而不是(或另外)一个模型对象,那么如何处理呢。我想您可以创建某种类型的存储库工厂并将其传入。但是存储库工厂不能解决诸如视图模型需要多个存储库,而这些存储库应该共享一个数据上下文以使更改是事务性的之类的问题。当您进入这样的场景时,DI容器应该只在合成根目录下使用的想法似乎开始崩溃。
[Export(typeof(IViewModelProvider))]
public class ViewModelProvider : IViewModelProvider
{
    private IUnityContainer _container;

    private ViewModelCache _viewModelCache;

    [ImportingConstructor]
    public ViewModelProvider(IUnityContainer container)
    {
        _container = container;
    }

    public T GetViewModel<T>(object model)
    {
        if (_viewModelCache.Contains<T>(model))
            return _viewModelCache.Get<T>(Model);

        var viewModel = _container.Resolve<T>();
        viewModel.Model = model;

        _viewModelcache.Cache(viewModel);

        return viewModel;         
    }
}