0

我有一個Mvc4 SPA項目我正在研究哪裏需要將多個視圖嵌套在一起的能力。視圖和視圖模型使用Durandal進行關聯。在Mvc4和Knockout中嵌套多個視圖 ViewModels

在Mvc3中,我之前通過在視圖中的局部視圖內使用局部視圖並將參數傳遞給局部視圖來完成此操作。這樣做,我可以在一對多關係上有多個部分,而這些關係又有多個部分顯示全部鏈接回父視圖的一對多關係。先前在MVC3使用

示例=

Public class ParentsController 
{ 
public ActionResult Parent(int id) 
{ 
    Parent parent = Db.Parents.Find(id); 
    ViewBag.ParentId = parent.Id; 
    return View(parent) 
} 

public PartialViewResult Child(int id) 
{ 
    Child childs = Db.Childs.Where(w => w.ParentId = id); 
    return PartialView("ChildPartial", childs.ToList()); 
} 

public PartialViewResult GrandChild(int id) 
{ 
    GrandChild grandChilds = Db.GrandChilds.Where(w => w.ChildId = id); 
    return PartialView("GrandChildPartial", grandChilds.ToList()); 
} 
} 

和視圖類似

Parent.cshtml 
@{ 
    ViewBag.Title = "Parent"; 
} 
@Html.DisplayFor(Model.ParentName) 
@{Html.RenderAction("ChildPartial", new { id = ViewBag.ParentId});} 


ChildPartial.cshtml 
@{ 
    ViewBag.Title = "Children"; 
} 
{ foreach (var child in childs) 
{ 
@{Html.DisplayFor(child.ChildsName)} 
@{Html.RenderAction("GrandChildPartial", new { id = ViewBag.ChildId});} 
}} 


GrandChildPartial.cshtml 
@{ 
    ViewBag.Title = "Grand Children"; 
} 
{ foreach (var grandChild in GrandChilds) 
{ 
@{Html.DisplayFor(grandChild.GrandChildsName)} 
}} 

同樣,上面的是我在過去使用的圖案的一個簡單的例子,不需要幫助。

我可以使用Breeze加載兒童並在父視圖模型中顯示相對容易的孩子,但是當我進入大孩子時,感覺就像進入'意大利麪條'代碼並從一個視圖模型加載太多。我認爲正確的做法是爲父母,孩子和孫子創建一個視圖模型,將它們分離出來並使它們可重用。

我的問題是父視圖模型應該加載孩子的視圖模型,然後讓孩子的視圖模型加載大孩子的視圖模型,或者應該有一個視圖從一個單獨的父對象到子對象組合和級聯?也就是說應該在一個視圖中分別加載3個視圖模型,還是應該有一個專門的父視圖模型,它調用所有三個視圖模型並加載它們或多或少相互獨立?我在這裏尋找最佳實踐,因爲SPA理念對我而言是比較新的。

回答

3

在這裏宣佈一個最佳實踐還爲時尚早......特別是當您的應用程序的實際工作流程和性能特徵未知時(可能此時不可知)。

一般來說,我們認爲如果每個虛擬機加載所需內容,而不是依靠主虛擬機來提供下級虛擬機,則會更好。這裏的本能就是你把它分解成單獨的虛擬機,這樣他們可以執行自己的責任......所以讓他們這樣做。主人成爲其子虛擬機的協調者,儘可能地保持其實施細節。

我們打算在下個月發佈一個名爲「TempHire」的新樣本,植根於「熱毛巾(ette)」,可能會提供一些指導。時機可能不適合你。但是你可以找到),我將總結(和過於簡單化),該樣品的,似乎有關你的問題的特徵:

  1. VM與根實體相關聯(在你的情況下,主,父)。

  2. 主虛擬機接收專用於該根實體工作流並使用根實體標識標記的「datacontext」(工作單元[UoW])。

  3. 「工作單元管理器」通過根實體ID創建和跟蹤UoW。如果您要求爲Parent-1申請UoW,它會爲您提供正在追蹤的一個或爲您創建一個新的。

  4. 這使得子虛擬機可以很容易地以一種相當分離的方式與主服務器和彼此共享數據上下文。主人不必通過嵌套的虛擬機鏈傳遞UoW。相反,每個虛擬機都注入「工作單元管理器」,並可以通過家長ID向「工作單元管理器」請求一個UoW;它會得到「其他人正在使用」的UoW。

  5. 現在,任何虛擬機都可以通過向UoW請求該數據來加載它需要的任何數據(或從UoW緩存中的數據中受益)。虛擬機不必「思考」是要求數據的第一個還是最後一個,數據是否在緩存中,數據是在開始時還是根據需要檢索。 UoW可以封裝這些細節,展示虛擬機使用的簡單「查詢」方法。

  6. 當然,UoW應該提供適當的「刷新」方法來應對過時...對每個應用程序中的每種類型都有不同的定義。

  7. 我們傾向於爲每個典型地圍繞根實體定向的任務定義「沙箱」。因此,Parent-1的主虛擬機擁有自己的擁有自己的EntityManager的UoW,而Parent-2的主VM擁有自己的擁有自己的EntityManager的UoW。通過這種方式,用戶可以同時在Parent-1和Parent-2上工作(例如,在更新訂單#456的同時創建訂單#123)並且獨立地不會混合更改。

  8. 「工作單元經理」使用嵌入式EntityManagers(EM)創建UoW。它使用名爲「EntityManagerProvider」的助手服務創建新的EM。 「EntityManagerProvider」負責分配新的EM並將其填入「全局數據」,例如參考列表(例如,狀態,狀態碼,顏色等)。

  9. 「EntityManagerProvider」(EMP)在內部保存了一個只讀的「主EM」,其源MetadataStore和這些靜態引用列表的規範版本。它創建的新EMs通常是這個隱藏主EM的副本。因此,整個系統對元數據和這些靜態引用列表提出一個請求。 EMP負責將該來源資料分發給其創建的新EM。

您需要多少錢?我不知道。

+0

病房感謝您的優秀和非常深入的答覆。我看到你的另一篇帖子使用UoW來引用TempHire。有興趣看到它,說實話,我仍然感覺哪些技術會起作用,所以我一定會密切關注它。我可能打算用這兩種方法來看看哪種最適合。 –

2

我的好友史蒂夫施密特提供了另一種必須考慮的攻擊途徑:One ViewModel/Multiple Views

在這種方法中,您編寫了不同的視圖,每個視圖專用於對根對象及其子對象圖的特定視角。這些與您原始提案的意見大致相同(如果不相同)。

有什麼不同?只有一個ViewModel! Durandal的「ko compose」定製Knockout綁定將多個視圖附加到同一個ViewModel是很容易的。您可以在佈局級別獲得很好的分離,而無需使用站立式並行虛擬機。

當傳遞模型的非可視化表示邏輯很簡單,但您希望從不同的角度(也就是「圍繞數據旋轉」)查看該模型時,此方法運行良好。

主/細節可以是一個簡單的例子。設想一個參考列表編輯器,其頂部的「網格」中的列表項目和右側的簡單表格顯示所選項目的詳細信息。這裏沒有太多的邏輯。爲什麼要打擾兩個虛擬機並且必須在「列表虛擬機」中將「虛擬機列表」中的項目列表與「編輯器虛擬機」中選定的項目進行協調?作爲單個虛擬機非常簡單。

在簡單情況下,這種方法非常有效,典型應用中有很多簡單的情況。

認爲這是對我的其他答案中描述的重型多虛擬機技術的補充。