使用 Unity 进行 MVVM 依赖注入,用于分层视图模型

Posted

技术标签:

【中文标题】使用 Unity 进行 MVVM 依赖注入,用于分层视图模型【英文标题】:MVVM dependency injection with Unity for layered view models 【发布时间】:2014-03-26 14:58:45 【问题描述】:

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

当您的视图模型需要创建需要创建其他视图模型的视图模型时,使用 Unity 之类的东西实现依赖注入的最佳方法是什么?

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

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

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

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

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

【问题讨论】:

我的回答有帮助吗?有更新吗? 确实有帮助。但是,我仍在努力解决我正在从事的项目中的其他无数问题,并且我仍在努力解决这些问题。我也在尝试使用存储库,并且我有一个类似的问题,即如何在较低级别实例化它们。如果您有创建 VM B 的 VM A 创建 VM C,则您的建议有效。但是,如果他们每个人都需要一个新的存储库实例而不是(或除了)模型对象,那么您将如何处理它。您可以创建某种类型的存储库工厂并将其传递给我。 但是存储库工厂并没有解决诸如如果视图模型需要多个存储库并且这些存储库应该共享数据上下文以便更改是事务性的。似乎当你遇到这样的场景时,DI 容器应该只在组合根中使用的想法开始崩溃。 【参考方案1】:

我已经使用 Autofac 和 MEF 建立了一个 MVVM 应用程序来解决您所说的问题。长话短说,我创建了一个服务接口IViewModelProvider,它为任意模型的视图模型提供服务。此服务的实现为所有 ViewModel 提供缓存,并在找不到特定模型的请求 ViewModel 类型的 ViewModel 时为模型创建 ViewModel。

ViewModelProvider 是一种它自己的 IoC 容器,它在初始化时反映所有加载的程序集,然后在运行时解决依赖关系。 ViewModelProvider 为IViewModelProvider 服务注册了自己的一个实例,因此可以将自己传递给ViewModels,这需要能够实例化新的 ViewModel。

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

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

以下代码是伪代码,混合了一些 MEF 和一些 Autofac 语法,但我认为它的含义很清楚:

获取 ViewModel 的接口:

public interface IViewModelProvider

    T GetViewModel<T>(object model);

导入 Unity 容器并使用它来解析尚未缓存的 ViewModel 的实现。 ViewModelCache 有点像你必须自己构建的高级字典。

[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;         
    

然后可以将该服务注入到您的 ViewModel 中,并且 ViewModel 可以创建自己的子 ViewModel,而不必关心这些子 ViewModel 是否已经存在或是否需要创建。

希望这会有所帮助。这是一个广泛的话题,所以请询问您是否有任何具体问题。

【讨论】:

以上是关于使用 Unity 进行 MVVM 依赖注入,用于分层视图模型的主要内容,如果未能解决你的问题,请参考以下文章

.NET6+WPFWPF使用prism框架+Unity IOC容器实现MVVM双向绑定和依赖注入

Unity 依赖注入

用于依赖注入的 MVC Web API 和 Unity

微软依赖注入Unity

运用Unity实现依赖注入[结合简单三层实例]

WPF 高级篇 MVVM (MVVMlight) 依赖注入使用Messagebox