在MVC中的嵌套ViewModels / 部分视图问题

5

我有两个视图:一个是局部视图,另一个是使用@Html.RenderPartial("_PartialView")封装局部视图的视图。每个都有自己的ViewModel:

public class PartialViewModel 
{
    // properties, etc.
}

public class MainViewModel 
{
    public PartialViewModel p { get; set; }
    // properties, etc.
}

当我加载第二个视图(使用MainViewModel的那个)时,出现了字典错误,因为这个视图和它封装的部分视图使用了两个不同的ViewModels。我不能让它们使用相同的ViewModel,因为这个部分视图在许多其他不同的视图中被渲染。
更明确地说,这两个视图都包含表单,其中部分视图代表所有表单之间共享的字段。鉴于此,我有任何选择吗,还是我只是试图做一些不符合MVC设计约束的事情?
2个回答

4

您需要稍微不同地设计这个。主视图将具有一个模型 - 让我们称之为 MainModel ,而局部视图可以具有一个模型 - 我们将其称为 PartialModel

public class PartialModel 
{
   /// props
}

public class MainViewModel 
{
    public PartialModel Partial { get; set; }
    // properties, etc.

    // per comments in other answer you may want something like this
    public MainViewModel()
    {
      Partial = new PartialModel();
    }
}

然后您的主视图将具有以下内容:
@model MainViewModel

然后在主视图的中间,您会看到类似以下内容:

@{ Html.RenderPartial("myPartialView", Model.Partial); }

请注意Html.RenderPartial周围的大括号,因为RenderPartial返回值是void。

当您呈现部分视图时,还可以将Model传递给它。如果它被正确设计,则部分所需的模型已经可以从主视图的模型中访问。


我认为这就是我所缺失的——@Html.RenderPartial的第二个参数。谢谢。 - alex
1
@alex,另外需要注意的是,如果在使用RenderPartial时没有指定模型,它将默认使用主视图的ViewDataDictionary,因此会将MainViewModel传递给局部视图。但由于局部视图期望的是PartialViewModel,所以会出现错误。 - user3559349

2
你可以这样做,但是在你的控制器中,你需要声明一个新的MainViewModel并将其分配给它的PartialViewModel一个新的PartialViewModel。
例如:
public class Controller {
    public ActionResult Index(){
        var mainViewModel = new MainViewModel { PartialViewModel = new PartialViewModel() };
        return View(mainViewModel);
    }
}

现在,我将把这些模型的创建委托给工厂,但这更高级且在重构之前并非必需。

为什么这个被点赞了?当你使用RenderPartial()时,你并没有调用控制器,而是直接渲染视图,模型必须从视图中传递。你必须像我的答案一样指定哪个模型。有些设计模式总是使用相同的视图模型,它们非常庞大,如果是这种情况,那么你可以只渲染partial视图而不指定模型,它将使用父视图中的相同模型。 - Scott Selby
@ScottSelby 它很可能被点赞是因为如果您尝试访问未初始化的子视图模型的属性,则会收到NullReferenceException,因为它不会默认初始化。 - C Bauer
只要主模型初始化它,它就会工作。这段代码只是在你执行RedirectToAction("action", "controller")时有所帮助,但与@Html.RenderPartial毫无关系。 - Scott Selby
只有在主模型初始化它时,它才会这样做。换句话说,默认情况下它不会这样做,OP需要这样做,否则页面将崩溃?我认为你的回答存在问题,因为它没有涵盖到这一点。他已经将你标记为答案,而我的答案将帮助那些未能初始化其子视图模型的人。你需要重新评估你的投票原因,因为显然有人发现我的贡献有价值,而你只是无缘无故地投票反对。 - C Bauer
是的 - 我明白你的意思,这可能会帮助到有类似问题的人。这仅发生在调用操作并且操作调用视图时,OP的问题是关于直接调用视图的。我相信 .Net 框架实际上会初始化一个新的默认版本的对象并防止出现错误。 - Scott Selby
想一想。你创建了一个带有子视图模型属性的视图模型。你初始化了你的视图模型,但是将子视图模型留空。然后你使用子视图模型作为renderpartial的参数(使用你的代码)。如果在子视图模型视图中的任何地方使用Model.{PropertyName}(例如,使用Model.Title显示标题),那么你就会得到null.Title。Boom,运行时异常无处不在。如果你确定这就是它的工作方式,请点下踩,但我正在构建一个遭受这种问题的网站。 - C Bauer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接