从组合根解析交互式请求的视图模型?

时间:2014-06-24 10:32:07

标签: c# wpf mvvm dependency-injection

我最近开始了一个遵循MVVM模式的WPF项目。我正在尝试一次性解析视图模型的对象图(在组合根中,即在应用程序的Startup事件处理程序中),以便不让任何其他类依赖于我的IoC容器:

public partial class App : Application
{
    private void OnStartup(object sender, StartupEventArgs e)
    {
       // Composition Root

       var container = new UnityContainer();

       container.RegisterType<IResidentListViewModel, ResidentListViewModel>();
       container.RegisterType<IMainViewModel, MainViewModel>();

       container.RegisterType<IDataService, DataService>();

       var mainWindow = new MainWindow(container.Resolve<IMainViewModel>());

       Current.MainWindow = mainWindow;
       mainWindow.Show();
    }
}

ResidentListViewModel依赖于IDataService:

private readonly IDataService dataService;

public ResidentListViewModel(IDataService dataService)
{
   if (dataService == null)
      throw new ArgumentNullException("dataService");

   this.dataService = dataService;
}

这不是问题,因为容器会解决该依赖关系。

但是,ResidentListviewModel有一个Residents属性,可以访问IDataService:

private readonly ObservableCollection<IResidentViewModel> residents = new ObservableCollection<IResidentViewModel>(); 

public ObservableCollection<IResidentViewModel> Residents
{
   get
   {
      if (this.residents == null)
         LoadResidents();

      return this.residents;
   }
}

当加载数据时,麻烦就开始了:

private async Task LoadResidents()
{
   if (!IsLoading)
   {
      IsLoading = true;

      var models = await this.dataService
         .ListResidents();

      var viewModels = models
         .OrderBy(m => m.Name)
         .ThenBy(m => m.Vorname)
         .Select(m => new ResidentViewModel(m.Z_PF, string.Format("{0}, {1}", m.Name, m.Vorname)));

      residents.Clear();

      foreach (var viewModel in viewModels)
         residents.Add(viewModel);

      IsLoading = false;
   }
}

我知道,我知道,反复加入一个ObservableCollection是不行的,但请在这里忍受我。看到那个闪亮的'新'关键字?那是真正的罪魁祸首。我不知道如何在不辞去服务定位器('实例工厂')的情况下摆脱它,根据我最喜欢的DI书籍作者Mark Seemann反过来是反模式(是的,我确实有这本书和会推荐给任何C#开发人员。

当然,我可以自己注入虚拟机列表,但是这会将数据检索移动到组合根目录(听起来像个坏主意),我可以很容易地想出用户选择的方案条目和代码必须根据选择检索数据,让我回到正方形。

所以问题是:有没有办法用组合根的同一个单一调用处理这个问题?

1 个答案:

答案 0 :(得分:4)

你很亲密。不是实例工厂反模式,而是abstract factory模式:

var viewModels = models
    .OrderBy(m => m.Name)
    .ThenBy(m => m.Vorname)
    .Select(m => residentViewModelFactory.CreateInstance(m));

residentViewModelFactory当然是通过构造函数注入作为接口提供的依赖,这使得一切都很好并且可以测试,当然 setup-able 来自组合根(你将工厂注册为组件)。