我在我的WPF应用程序中使用构造函数依赖注入,但经常遇到以下模式,因此希望听取他人的意见并了解其他解决方案。
目标是将一组ViewModel的层次结构与类似的Model层次结构相连接,以便每个模型的信息呈现责任都落在其自己的ViewModel实现上。(该模式也会在其他情况下出现,但MVVM应该是一个很好的例子。)
这里是一个简化的例子。假设我有一个包含进一步模型集合的模型:
public interface IPerson
{
IEnumerable<IAddress> Addresses { get; }
}
public interface IAddress
{
}
我想在ViewModel中反映这个层次结构,以便我可以将ListBox(或其他控件)绑定到Person ViewModel中的集合:
public interface IPersonViewModel
{
ObservableCollection<IAddressViewModel> Addresses { get; }
void Initialize();
}
public interface IAddressViewModel
{
}
子ViewModel需要呈现子Model的信息,因此通过构造函数进行注入:
public class AddressViewModel : IAddressViewModel
{
private readonly IAddress _address;
public AddressViewModel(IAddress address)
{
_address = address;
}
}
问题是,如何最好地将子模型提供给相应的子视图模型?
这个例子很简单,但在典型的实际情况下,视图模型有更多的依赖项——每个依赖项都有自己的依赖项(依此类推)。我正在使用Unity 1.2(虽然我认为这个问题对其他IoC容器也是相关的),我正在使用Caliburn的视图策略来自动找到并连接适当的视图到视图模型。
这是我的当前解决方案:
父视图模型需要为每个子模型创建一个子视图模型,因此在初始化期间,它在构造函数中添加了一个工厂方法,供其使用:
public class PersonViewModel : IPersonViewModel
{
private readonly Func<IAddress, IAddressViewModel> _addressViewModelFactory;
private readonly IPerson _person;
public PersonViewModel(IPerson person,
Func<IAddress, IAddressViewModel> addressViewModelFactory)
{
_addressViewModelFactory = addressViewModelFactory;
_person = person;
Addresses = new ObservableCollection<IAddressViewModel>();
}
public ObservableCollection<IAddressViewModel> Addresses { get; private set; }
public void Initialize()
{
foreach (IAddress address in _person.Addresses)
Addresses.Add(_addressViewModelFactory(address));
}
}
一个满足 Func<IAddress, IAddressViewModel>
接口的工厂方法被注册到主 UnityContainer
。该工厂方法使用一个子容器来注册 ViewModel 所需的 IAddress
依赖项,然后解析子 ViewModel:
public class Factory
{
private readonly IUnityContainer _container;
public Factory(IUnityContainer container)
{
_container = container;
}
public void RegisterStuff()
{
_container.RegisterInstance<Func<IAddress, IAddressViewModel>>(CreateAddressViewModel);
}
private IAddressViewModel CreateAddressViewModel(IAddress model)
{
IUnityContainer childContainer = _container.CreateChildContainer();
childContainer.RegisterInstance(model);
return childContainer.Resolve<IAddressViewModel>();
}
}
现在,当初始化PersonViewModel
时,它遍历模型中的每个Address
并调用CreateAddressViewModel()
(这是通过Func<IAddress, IAddressViewModel>
参数注入的)。CreateAddressViewModel()
创建一个临时子容器并注册IAddress
模型,以便从子容器解析IAddressViewModel
时,通过其构造函数将正确的实例注入AddressViewModel
。
对我来说,这似乎是一个不错的解决方案,因为ViewModel的依赖关系非常清晰,并且易于测试,且不知道IoC容器。另一方面,性能还可以,但不是很好,因为可能会创建大量临时子容器。此外,我最终得到了许多非常相似的工厂方法。
- 这是使用Unity将子模型注入子ViewModel的最佳方法吗?
- 是否有更好(或更快)的方式在其他IoC容器(例如Autofac)中执行此操作?
- 如果给定MEF,该如何解决这个问题,考虑到它不是传统的IoC容器,但仍然用于组合对象?