2011-06-07 81 views
27

這是自從我開始使用MVVM以來,我一直在努力的一個問題,首先在WPF中,現在在Silverlight中。MVVM和IOC:處理查看模型的類不變量

我使用IOC容器來管理Views和ViewModels的分辨率。視圖往往是非常基本的,有一個默認的構造函數,但ViewModels傾向於訪問真正的服務,所有這些都是構建所需的。再次,我使用IOC容器來解決問題,所以注入服務不是問題。

成爲問題的是將所需數據通過IOC傳遞給ViewModel。作爲一個簡單的例子,考慮一個允許編輯客戶的屏幕。除了可能需要的任何服務之外,此屏幕的ViewModel還需要客戶對象來顯示/編輯客戶的數據。當做任何類型的(非MVVM)庫開發時,我認爲它是一個不可修改的規則,類不變量是通過構造函數傳遞的。如果我需要上下文相關的數據來建造課程時間所討論的類是容器管理的,我傾向於使用抽象工廠*作爲橋樑。在MVVM中,這看起來像是矯枉過正,因爲大多數ViewModel都需要自己的工廠。 (1)初始化/加載方法,其中我傳遞數據,這違反了通過構造函數強制類不變量的規則,(2)通過容器傳遞數據,如下所示:參數覆蓋(Unity),以及(3)通過全局狀態包(ugh)傳遞數據。

將特定於上下文的數據從一個ViewModel傳遞到下一個的一些備選方法是什麼?是否有任何MVVM框架解決這個特定的問題?

* 它可能有它自己的問題,例如要求在對Container.Resolve()的調用之間進行選擇,或者沒有對ViewModel進行容器管理。溫莎城堡有一個很好的解決方案,但AFAIK沒有其他框架。

編輯:

我忘了補充:一些我列出的選項中甚至沒有可能的,如果你正在做的「檢視首個」 MVVM,除非你先通過數據的視圖,然後到視圖模型。

+3

謝謝你提出這個問題。我偶然發現瞭如何將數據傳遞給ViewModel的困境。幸運的是,使用autofac的自動生成委託工廠,我只有不必一路去聲明一個全接口聲明的工廠,但它仍然是非常冗長。 – Ants 2011-06-15 06:49:01

回答

5

我曾經在這個問題上掙扎很多。據我所知,目前還沒有其他可行的方法。你似乎已經自己深深地思考了這件事。 我只是想要兩個添加在原因我 0.5美分爲什麼我經常選擇的選項(1):

  1. init方法是簡單的比任何其他的選擇來實現(當然,溫莎的類型化工廠也一樣簡單);
  2. 沒有構造函數參數的設計弱點可以減輕,以後在VM生命週期中強制檢查初始化參數
  3. 您要調用init方法的「地點」與您將調用構造函數的地方相同(或抽象工廠);
  4. 不同於抽象工廠,你可以分析出在特定接口的init()方法,以處理多個VM不同繼承路徑上(如果neeeded);
  5. 這是一個公平的妥協(在這種情況下至少):如果你真的無法忍受它,只是去工廠的解決方案,而無需關心(非常小的)的複雜性開銷。
7

我不太清楚問題是什麼,所以我會用一個簡單而人爲的例子。

假設您有一個CustomerListViewModel,其中列出了每位客戶的摘要。選擇客戶時,您想要顯示CustomerDetailViewModel。這可以採用客戶ID或ICustomer類型,此類型先前在CustomerListViewModel中填入客戶詳細信息(取決於您想要何時加載數據)。

我想你要問的是如果CustomerDetailViewModel也需要一系列服務作爲你想通過容器解析的依賴(通常是依賴鏈)。

由於您先做視圖模型,您需要從CustomerListViewModel實例化CustomerDetailViewModel,並且您希望通過容器來實現,以便適當地注入依賴關係。

因此,你提到,你通常會通過一個抽象工廠模式做到這一點,例如ICustomerDetailViewModelFactory這被作爲對CustomerListViewModel服務過去了。

此工廠類型有一個ICustomerDetailViewModel GetCustomerDetailViewModel(ICustomer customer)方法。此工廠類型將需要對您的IoC容器的引用。

當你GetCustomerDetailViewModel工廠方法解決ICustomerDetailViewModel,你可以指定你想,當你調用解決您的容器上使用的ICustomer構造函數的參數值。

例如,Unity有parameter overrides,請參閱here獲取Castle Windsor支持。溫莎城堡也有typed factory facility,所以你不需要實施具體的工廠類型,只需要抽象。

所以我會選擇2!我們使用Caliburn.Micro,它解決了很多MVVM問題,但我不知道解決此問題的任何框架。

2

我不太確定MVVM和IoC是否適合在構造函數中使用類不變量。根據我的經驗,是的ViewModels作爲ICommand.Execute的結果,它允許一個簡單的兩個階段的過程中產生的:

var vm = Container.Resolve<CustomerViewModel>(); 
vm.Model = CustomerRepository.GetCustomerModel(id); 

在這個階段,我的看法沒有視圖模型的知識,而只會發生當我注入ViewModel到任何容器綁定到視圖。我也使用DataTemplates來渲染ViewModel,這意味着我不必直接實例化View來提供DataContext。

所以,要回答,我會使用(1),並打破「規則」。