我在我的WPF应用程序中使用构造函数依赖注入,并且我一直运行到以下模式,因此想要获得其他人的意见并听取其他解决方案。如何使用构造函数依赖注入将模型从集合提供给ViewModels?
目标是将ViewModel的层次结构连接到类似的Models的层次结构,以便在每个模型中呈现信息的责任在于它自己的ViewModel实现。 (这种模式在其他情况下也会出现,但MVVM应该是一个很好的例子。)
这是一个简化的例子。既然我有了进一步的模型集合的模式:
public interface IPerson
{
IEnumerable<IAddress> Addresses { get; }
}
public interface IAddress
{
}
我想反映这个层次的的ViewModels,这样我可以绑定一个列表框(或其他)在人视图模型的集合:
public interface IPersonViewModel
{
ObservableCollection<IAddressViewModel> Addresses { get; }
void Initialize();
}
public interface IAddressViewModel
{
}
子视图模型需要出示从子模型的信息,所以它是通过构造函数注入:
public class AddressViewModel : IAddressViewModel
{
private readonly IAddress _address;
public AddressViewModel(IAddress address)
{
_address = address;
}
}
的问题是,什么是最好的方法将子模型提供给相应的子ViewModel?
该示例很简单,但在典型的实际情况下,ViewModel有更多的依赖关系 - 每个依赖关系都有自己的依赖关系(依此类推)。我使用的是Unity 1.2(尽管我认为这个问题在其他IoC容器中是相关的),而且我正在使用Caliburn的视图策略来自动查找并将适当的View连接到ViewModel。
这是我目前的解决方案:
视图模型需要创建一个子视图模型为每个孩子型号的父母,所以它有一个工厂方法添加到它的构造,它初始化过程中使用:
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
中注册。工厂方法使用一个子容器注册由视图模型所需的IAddress
依赖,然后解决了孩子视图模型:
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容器。另一方面,性能是好的,但不是很好,因为可以创建大量的临时子容器。另外,我最终得到了很多非常类似的工厂方法。
- 这是最好的方式注入子模型到子ViewModels与统一?
- 有没有更好的(或更快)的方式去做其他IoC容器,例如Autofac?
- 怎么会这个问题,MEF加以解决,因为它不是一个传统的IoC容器,但仍用于合成的对象?
正如你指出的指定参数是否有任何相关性需要的型号,这一直是我的一个搅局者不起作用。 虽然重新使用子容器是一种可能性。 – GraemeF 2010-05-10 16:18:53