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

时间:2014-03-26 14:58:46

标签: mvvm view model dependency-injection unity-container

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

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

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

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

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

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

那么解决此方案的UserViewModel实例的最佳方法是什么?我可以将IUnityContainer的一个实例传递给UsersViewModel,然后用它来解决它们,但是根据我的阅读,这是一个坏主意。怎么办呢?

1 个答案:

答案 0 :(得分:1)

我已经使用Autofac和MEF设置了MVVM应用程序来解决您正在谈论的问题。总而言之,我创建了一个服务接口IViewModelProvider,为任意模型提供ViewModel服务。如果找不到特定模型所请求的ViewModel类型的ViewModel,则此服务的实现为所有ViewModel提供缓存并为模型创建ViewModel。

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

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

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

下面的代码是伪代码,将一些MEF与一些Autofac语法混合在一起,但我认为它清楚了解它是什么:

获取ViewModels的界面:

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,而不必关心这些是否已经存在,因为或者需要创建它们。

希望这会有所帮助。这是一个广泛的主题,所以请问你是否有任何特别的问题。