我有一个MVC表单,它比我的所有其他表单更复杂,使用了三个模型。
{p>Company -> Base_IP -> RequestedIP
ViewModel -> Partial1 -> Partial2
我正在使用BeginCollectionItem,因为每个模型都有一个模型的属性列表。 IE - 公司有一个名为baseIps的属性,BaseIp类有一个名为requestedIps的属性,它是requestedIps
,它返回null,计数在页面渲染上,但是没有提交。
在post
Create()中提交到数据库时,我会在' requestedIps'上获得空值。财产,这是为什么?
我已经在下面添加了违规控制器和部分代码示例,而不是整个事情,因为它是大量/多余的 - 如有问题,请告诉我。
控制器 - [HttpGet]创建()
public ActionResult Create()
{
var cmp = new Company
{
contacts = new List<Contact>
{
new Contact { email = "", name = "", telephone = "" }
}, pa_ipv4s = new List<Pa_Ipv4>
{
new Pa_Ipv4
{
ipType = "Pa_IPv4", registedAddress = false, existingNotes = "", numberOfAddresses = 0, returnedAddressSpace = false, additionalInformation = "",
requestedIps = new List<IpAllocation>
{
new IpAllocation { allocationType = "Requested", cidr = "", mask = "", subnet = "" }
}
}
}
};
return View(cmp);
}
控制器 - [HttpPost]创建()
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Company cmp) // does not contain properties assigned/added to in view render
{
if (ModelState.IsValid)
{
db.companys.Add(cmp);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(cmp);
}
创建视图
@model Company
@using (Html.BeginForm())
{
<div id="editorRowsAsn">
@foreach (var ip in Model.pa_ipv4s)
{
@Html.Partial("Pa_IPv4View", ip)
}
</div>
<br />
<div data-role="main" class="ui-content">
<div data-role="controlgroup" data-type="horizontal">
<input type="submit" class="ui-btn" value="Create" />
</div>
</div>
}
Pa_Ipv4查看
@model Pa_Ipv4
@using (Html.BeginCollectionItem("pa_ipv4s"))
{
@Html.AntiForgeryToken()
<div id="editorRowsRIpM">
@foreach (var item in Model.requestedIps)
{
@Html.Partial("RequestedIpView", item)
}
</div>
@Html.ActionLink("Add", "RequestedManager", null, new { id = "addItemRIpM", @class = "button" }
}
RequestedIpView
@model IpAllocation
<div class="editorRow">
@using (Html.BeginCollectionItem("requestedIps"))
{
<div class="ui-grid-c ui-responsive">
<div class="ui-block-a">
<span>
@Html.TextBoxFor(m => m.subnet, new { @class = "checkFiller" })
</span>
</div>
<div class="ui-block-b">
<span>
@Html.TextBoxFor(m => m.cidr, new { @class = "checkFiller" })
</span>
</div>
<div class="ui-block-c">
<span>
@Html.TextBoxFor(m => m.mask, new { @class = "checkFiller" })
<span class="dltBtn">
<a href="#" class="deleteRow"><img src="~/Images/DeleteRed.png" style="width: 15px; height: 15px;" /></a>
</span>
</span>
</div>
</div>
}
</div>
答案 0 :(得分:2)
您首先(外部)部分将生成与您的模型相关的正确名称属性(您的代码未显示Pa_Ipv4.cshtml
视图中的任何控件,但我假设您确实有一些),例如
<input name="pa_ipv4s[xxx-xxx].someProperty ...>
然而内部部分不会因为@using (Html.BeginCollectionItem("requestedIps"))
将生成
<input name="requestedIps[xxx-xxx].subnet ...>
<input name="requestedIps[xxx-xxx].cidr ...>
他们应该在哪里
<input name="pa_ipv4s[xxx-xxx].requestedIps[yyy-yyy].subnet ...>
<input name="pa_ipv4s[xxx-xxx].requestedIps[yyy-yyy].cidr ...>
通常,您可以使用其他视图数据将前缀传递给partial(请参阅this answer以获取示例),但遗憾的是,您无法访问Guid
生成的BeginCollectionItem
} helper因此无法正确添加name
属性的前缀。
文章here和here讨论创建自己的帮助程序来处理嵌套集合。
其他选项包括使用嵌套的for
循环并包含集合索引器的隐藏输入,这将允许您从集合中删除项目,并且在提交表单时仍能够绑定到模型。
for (int i = 0; i < Model.pa_ipv4s.Count; i++)
{
for(int j = 0; j < Model.pa_ipv4s[i].requestedIps.Count; j++)
{
var name = String.Format("pa_ipv4s[{0}].requestedIps.Index", i);
@Html.TextBoxFor(m => m.pa_ipv4s[i].requestedIps[j].subnet)
@Html.TextBoxFor(m => m.pa_ipv4s[i].requestedIps[j].cidr)
...
<input type="hidden" name="@name" value="@j" />
}
}
答案 1 :(得分:1)
如果查看最终标记,您可能会输入名称为
的输入input name="subnet"
input name="cidr"
input name="mask"
这是表单发布时表单集合的显示方式。不幸的是,这不会绑定到您的公司模型。
您的字段需要看起来像这样
input name="Company.pa_ipv4s[0].subnet"
input name="Company.pa_ipv4s[0].cidr"
input name="Company.pa_ipv4s[0].mask"
input name="Company.pa_ipv4s[1].subnet"
input name="Company.pa_ipv4s[1].cidr"
input name="Company.pa_ipv4s[1].mask"
答案 2 :(得分:0)
有多种方法可以“修复”这个问题,每个方法都有自己的注意事项。
一种方法是设置“编辑器”视图(通常在〜/ Views / Shared / EditorTemplates / ClassName .cshtml中),然后使用@ Html.EditorFor(x =&gt; x.SomeEnumerable) )。 在您需要能够从集合中间删除任意项目的情况下,这将无法正常工作;虽然你仍然可以通过你设置的ItemIsDeleted
等额外属性来处理这些情况(例如通过javascript)。
在这里设置一个完整的示例会很冗长,但您也可以参考本教程:http://coding-in.net/asp-net-mvc-3-how-to-use-editortemplates/
首先,您将创建一个简单的模板,如
~/Views/Share/EditorTemplates/Contact.cshtml
:
@model yournamespace.Contact
<div>
@Html.LabelFor(c => c.Name)
@Html.TextBoxFor(c => c.Name)
@Html.ValidationMessageFor(c => c.Name)
</div>
<div>
@Html.LabelFor(c => c.Email)
@Html.TextBoxFor(c => c.Email)
@Html.ValidationMessageFor(c => c.Email)
</div>
... other simple non-enumerable properties of `Contact` ...
@Html.EditorFor(c => c.pa_ipv4s) @* uses ~/Views/Shared/EditorTemplates/pa_ipv4s.cshtml *@
在您编辑/创建Company
的视图中,您可以将其调用为
@Html.EditorFor(company => company.Contacts)
(就像EditorTemplate for Company调用EditorFor pa_ipv4s一样。)
当您以这种方式使用EditorFor时,MVC将自动为您处理索引。 (你如何处理添加一个新的联系人/ IPv4 /等。这是一个更高级,但这应该让你开始。)
MVCContrib也有一些你可以使用的辅助方法,但是我记得并不是特别简单,可能会让你陷入特定的MVC版本。