0

我有一个正在处理的 Mvc4 SPA 项目,我需要能够将多个视图相互嵌套。视图和视图模型使用 Durandal 链接起来。

在 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 的想法对我来说相对较新。

4

2 回答 2

3

在这里宣布最佳实践还为时过早……尤其是当您的应用程序的实际工作流程和性能特征未知时(此时可能不知道)。

一般来说,我们认为每个虚拟机都加载它需要的东西而不是依靠主虚拟机来为从属虚拟机提供服务会更好。这里的直觉是你把它分解成单独的虚拟机,这样它们就可以执行自己的职责......所以让他们去做吧。主节点成为其子虚拟机的协调者,并尽可能远离他们的实现细节。

我们打算在下个月左右发布一个名为“ TempHire ”的新样本,它植根于“Hot Towel(ette)”,可能会提供一些指导。时间可能不适合你。但是您可以在 GitHub 上找到代码),我将总结(并过度简化)该示例的与您的问题相关的功能:

  1. 主 VM 与根实体(在您的情况下为父实体)相关联。

  2. 主 VM 接收专用于该根实体的工作流并标有根实体 ID 的“数据上下文”(工作单元 [UoW])。

  3. “工作单元管理器”通过根实体 ID 创建和跟踪 UoW。如果您要求 Parent-1 的 UoW,它会为您提供它正在跟踪的 UoW,或者为您创建一个新的。

  4. 这使得子虚拟机可以轻松地与主虚拟机共享数据上下文,并且以一种相当解耦的方式彼此共享。主服务器不必通过嵌套 VM 链传递 UoW。相反,每个 VM 都被注入了“工作单元管理器”,并且可以通过父 ID 向“工作单元管理器”请求一个 UoW;它将获得“其他人都在使用”的 UoW。

  5. 现在,任何 VM 都可以通过向 UoW 请求数据来加载它需要的任何数据(或从 UoW 缓存中的数据中受益)。虚拟机不必“考虑”它是第一个还是最后一个请求数据,数据是否在缓存中,数据是在开始时全部检索还是根据需要检索。UoW 可以封装这些细节,公开简单的“查询”方法供 VM 使用。

  6. 当然,UoW 应该提供适当的“刷新”方法来应对陈旧性......对于每个应用程序中的每种类型都有不同的定义。

  7. 我们倾向于为每个任务“沙箱化”UoW,这些任务通常围绕根实体进行。因此,Parent-1 的主 VM 有自己的 UoW 和自己的 EntityManager,而 Parent-2 的主 VM 有自己的 UoW 和自己的 EntityManager。通过这种方式,用户可以同时在 Parent-1 和 Parent-2 上工作(例如,在更新订单 #456 的同时创建订单 #123)并且独立地工作,而不会混合更改。

  8. “工作单元管理器”创建带有嵌入式实体管理器 (EM) 的 UoW。它使用名为“EntityManagerProvider”的辅助服务创建新的 EM。“EntityManagerProvider”负责铸造新的 EM 并用“全局数据”填充它们,例如参考列表(例如,状态、状态代码、颜色等)。

  9. “EntityManagerProvider”(EMP)在内部保留一个只读的“主 EM”,其中包含源 MetadataStore 和这些静态引用列表的规范版本。它创建的新 EM 通常是这个隐藏的主 EM 的副本。因此,整个系统只对元数据发出一个请求,对那些静态引用列表发出一个请求。EMP 负责将源材料分发给它创建的新 EM。

你需要多少这个?我不知道。

于 2013-04-02T18:11:43.013 回答
2

我的好友 Steve Schmidt 提供了另一种必须考虑的攻击途径:一个 ViewModel / Multiple Views

在这种方法中,您可以组合不同的视图,每个视图都专用于根实体及其子对象图的特定视角。这些与您原始提案的意见大致相同(如果不相同)。

有什么不同?只有一个视图模型!使用 Durandal 的“ko compose”自定义 Knockout 绑定可以轻松地将多个视图附加到同一个 ViewModel。您可以在布局级别获得很好的分离,而无需建立并行 VM。

当提供模型的非可视化表示逻辑很简单但您想从不同的角度(AKA,“围绕数据旋转”)查看该模型时,这种方法很有效。

Master/Detail 可以是一个简单的例子。想象一个参考列表编辑器,列表项位于顶部的“网格”中,右侧有一个简单的表单,显示所选项目的详细信息。这里没有太多逻辑。为什么要为两个虚拟机而烦恼,并且必须将“列表虚拟机”中的项目列表与“编辑器虚拟机”中的选定项目协调?作为单个虚拟机要简单得多。

这在简单的情况下工作得非常好,在典型的应用程序中有很多简单的情况。

将此视为对我的其他答案中描述的重型多 VM 技术的补充。

于 2013-04-02T19:03:35.883 回答