发布一个带有多个部分视图的表单

34

我正在尝试提交由两个强类型视图组成的表单。这个问题很相似,但没有答案:

MVC 3 Razor Form Post w/ Multiple Strongly Typed Partial Views Not Binding

当我提交表单时,提交到控制器的模型始终为null。我花了几个小时来尝试使它工作。这似乎应该很简单。我错过了什么吗?我不需要做ajax,只需要能够发布到控制器并呈现一个新页面。

谢谢

这是我的视图代码:

<div>
    @using (Html.BeginForm("TransactionReport", "Reports", FormMethod.Post, new {id="report_request"}))
    {
        ViewContext.FormContext.ValidationSummaryId = "valSumId";
        @Html.ValidationSummary(false, "Please fix these error(s) and try again.", new Dictionary<string, object> { { "id", "valSumId" } });
        @Html.Partial("_ReportOptions", Model.ReportOptions);
        @Html.Partial("_TransactionSearchFields", new ViewDataDictionary(viewData) { Model = Model.SearchCriteria });
    }

这是控制器中的代码:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult TransactionReport(TransactionReportRequest reportRequest)
{
    var reportInfo = new List<TransactionReportItem>();

    if (ModelState.IsValid)
    {
        var reportData = _reportDataService.GetReportData(Search.MapToDomainSearchCriteria(reportRequest.SearchCriteria));
        if (reportData!=null)
        {
            reportInfo = reportData.ToList();
        }
        return View(reportInfo);
    }
    return View(reportInfo);
}

这些局部视图本身并不重要,因为它们所做的只是绑定和显示它们的模型。


你的提交按钮在哪里?它需要在表单标签内。我不确定你是没有包含它还是放在标签外面了。 - CD Smith
5个回答

56

这里不应该使用部分视图,你需要使用EditorTemplates,因为它们是用于你想要的功能的。在这种情况下,你的属性将与你提交的模型很好地绑定。

你的主视图将包含此表单(请注意,你只需要使用EditorFor而不是Partial;在这种情况下,你可能需要将viewData参数放在ViewBag中):

@using (Html.BeginForm("TransactionReport", "Reports", FormMethod.Post, new {id="report_request"}))
{
    ViewContext.FormContext.ValidationSummaryId = "valSumId";
    @Html.ValidationSummary(false, "Please fix these error(s) and try again.", new Dictionary<string, object> { { "id", "valSumId" } });
    @Html.EditorFor(model => model.ReportOptions);
    @Html.EditorFor(model = Model.SearchCriteria });
}
现在你只需要将你的部分视图拖到文件夹~/Shared/EditorTemplates/并将它们重命名为与它们所对应的模型名称相同的名称,它们就是编辑器模板。
~/Shared/EditorTemplates/文件夹中,创建一个新的“视图”,例如“SearchCriteria.cshtml”。在内部,将“model”设置为您要创建编辑器模板的类的类型。例如(示例类具有属性NameOtherCriteria):
@model MyNamespace.SearchCriteria
<ul>
    <!-- Note that I also use EditorFor for the properties; this way you can "nest" editor templates or create custom editor templates for system types (like DateTime or String or ...). -->
    <li>@Html.LabelFor(m => m.Name): @Html.EditorFor(m => m.Name)</li>
    <li>@Html.LabelFor(m => OtherCriteria): @Html.EditorFor(m => m.OtherCriteria</li>
</ul>

一些关于它们的好文章:


1
是的,这是一个更好的解决方案。Grails有类似的东西,我应该使用grails术语谷歌(我是说必应)一下 :) 这个很棒!感谢你的帮助! - dalcantara
4
在某些技术领域,如果你不知道正确的术语,有时很难找到你需要的东西。 - Styxxy
由于链接已经失效,这里提供一个关于EditorTemplates的好教程。 - bnu
2
@bnu:感谢您的通知。我用两个好的替代链接替换了旧链接,并添加了一些小的示例代码。 - Styxxy

13

你应该给PartialView的字段添加前缀。这样可以正确地绑定数据。

所以不要这样写:

@Html.Partial("_ReportOptions", Model.ReportOptions);

使用:

@Html.Partial("_ReportOptions", Model.ReportOptions, new ViewDataDictionary { TemplateInfo = new TemplateInfo { HtmlFieldPrefix = "ReportOptions" }})

10

我同意@Styxxy和@Tony的观点,编辑模板是更好的解决方案。然而,你的问题在于你正在将子模型提供给局部视图。因此,当局部视图呈现时,它不知道它是较大模型的一部分,并且不会生成正确的名称属性。

如果你坚持使用部分视图而不是编辑模板,那么我建议只向部分视图传递模型,然后让每个部分执行Model.Whatever.Foo,它将为绑定生成正确的名称属性。


4

2
@Html.Partial("_ReportOptions", Model.Contact, new ViewDataDictionary()
           {
               TemplateInfo = new TemplateInfo()
                   {
                       HtmlFieldPrefix = "Contact"
                   }
           })

)


@Html.Partial("_TransactionSearchFields", Model.SearchCriteria, new  
 ViewDataDictionary()
           {
               TemplateInfo = new TemplateInfo()
                   {
                       HtmlFieldPrefix = "SearchCriteria"
                   }
           })

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