2014-06-24 42 views
3

我最近啓動了一個遵循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有命中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#開發人員)。

我當然可以注入虛擬機本身的列表,但這會將數據檢索移動到合成根目錄(聽起來像一個壞主意),我可以輕鬆想出一個場景,用戶選擇一個條目和代碼必須根據選擇檢索數據,讓我回到原點。

所以問題是:有沒有辦法解決這個問題,從同一個單一的調用組合根?

回答

4

你就近了。不實例工廠反模式,但abstract factory圖案:

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

residentViewModelFactory是作爲通過構造注入,這使得一切細和可測試接口提供當然依賴性,和從組合物當然設置-能夠根(您註冊工廠作爲組件之一)。

+0

使用容器和構造函數注入而不是靜態(讀取:全局)服務定位器註冊工廠:) –

+1

+1,儘管AFAICT,residentViewModelFactory不是工廠方法,而是一個抽象工廠。 –

+0

@MarkSeemann:你的意思是''ResidentViewModelFactory'(class)是一個*抽象工廠*,而'CreateInstance'是所謂抽象工廠的工廠方法* –