你好,在互联网上,我有一个有趣的难题:
是否可以绑定视图以创建对象,如果该对象包含纯粹使用MVC视图/部分视图的其他对象的列表?
男人,这一切都很复杂......让我给你一个快速的代码示例,说明我的意思:
Models:
public class ComplexObject
{
public string title { get; set; }
public List<ContainedObject> contents { get; set; }
}
public class ContainedObject
{
public string name { get; set; }
public string data { get; set; }
}
好看又简单吧?好的,因此创建其中一个的强类型视图对于“title”属性来说非常简单:
something like:
@Html.TextBoxFor(x => x.title)
但我无法找到一种使用MVC绑定“ContainedObjects”列表的好方法。我得到的最接近的是使用“List”脚手架模板创建一个强类型的IEnumerable局部视图,并将其包含在页面上。
在不添加样式等的情况下,该局部视图的默认外观为:
@model IEnumerable<MVCComplexObjects.Models.ContainedObject>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
@Html.DisplayNameFor(model => model.name)
</th>
<th>
@Html.DisplayNameFor(model => model.data)
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.name)
</td>
<td>
@Html.DisplayFor(modelItem => item.data)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
@Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
@Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
</td>
</tr>
}
</table>
但坦率地说,我无法弄清楚如何将其包含在创建新的ComplexObject中。换句话说,我可以通过绑定显示已存在的ContainedObjects列表,如下所示: @ Html.Partial(“PartialCreate”,Model.contents)
但我想我想要的是:
@Html.PartialFor("PartialCreate", x => x.contents)
我应该注意到,使用Javascript编写代码并没有太多麻烦(我将在下面包含代码),但我真的很想知道是否有一种纯粹使用MVC的方法。我最近从WebForms转换(我几乎只是用AJAX调用替换了所有的回发)在我工作的项目中出现了很多这样的事情。
无论如何,这就是我目前的做法:
Html -
Name: <input type="text" id="enterName" />
Data: <input type="text" id="enterData" />
<a id="addItem">Add Item</a>
<ul id="addedItems">
</ul>
<a id="saveAll">Save Complex Object</a>
Javascript -
<script>
var contents = [];
$(document).ready(function () {
$('#addItem').click(function () {
var newItem = { name: $('#enterName').val(), data: $('#enterData').val() };
contents.push(newItem);
$('#addedItems').html('');
for (var i = 0; i < contents.length; i++) {
$('#addedItems').append(
"<li>" + contents[i].name + ", " + contents[i].data + "</li>"
);
}
});
$('#saveAll').click(function () {
var toPost = { title: "someTitle", contents: contents };
$.ajax({
url: '/Home/SaveNew',
type: 'POST',
data: JSON.stringify(toPost),
dataType: 'json',
contentType: 'application/json; charset=utf-8',
success: function (data, textStatus, jqXHR) {
alert("win");
},
error: function (objAJAXRequest, strError) {
alert("fail");
}
});
});
});
</script>
这不是一个糟糕的解决方案或任何东西,我只是不想每次我想保存一个新对象时都要实现Javascript调用,而是在其他地方使用标准的Razr代码。我希望全面合理。
是否还有其他人遇到此问题并找到了解决方案?
答案 0 :(得分:3)
阅读这篇文章:
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
然后读一下:
http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/
这些文章适用于MVC2,但可以在3和4中使用。
答案 1 :(得分:1)
我最近发现自己需要完成相同的任务,就像你一样,不想添加一堆javascript。我正在使用MVC4,而且我可以说,似乎并不是一种将模型的可枚举属性绑定到视图的开箱即用方法。 :(
但是,正如您在问题中所示,可能从视图中的模型中检索可枚举属性。诀窍是将更新恢复到控制器。关闭您的示例模型,您的视图可能看起来像这样(您不需要做出部分):
@model MVCComplexObjects.Models.ComplexObject
<p>
@Html.ActionLink("Create New", "Create")
</p>
@using (Html.BeginForm("SaveNew", "Home", FormMethod.Post))
{
<table>
<tr>
<th>
@Html.DisplayNameFor(model => model.contents[0].name)
</th>
<th>
@Html.DisplayNameFor(model => model.contents[0].data)
</th>
<th></th>
</tr>
@for (int i = 0; i < Model.contents.Count; i++)
{
<tr>
<td>
@Html.TextBox("updatedContents["+i+"].name", Model.contents[i].name)
</td>
<td>
@Html.TextBox("updatedContents["+i+"].data", Model.contents[i].data)
</td>
<td>
@* Got rid of the edit and detail links here because this form can now act as both *@
@Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
</td>
</tr>
}
</table>
<input type="submit" value="Save" />
}
你的控制器动作看起来像这样:
[HttpPost]
public ActionResult SaveNew(ICollection<ContainedObject> updatedContents)
{
foreach (var co in updatedContents)
{
//Update the contained object...
}
return RedirectToAction("Index");
}
基本上,我们在视图中定义一个新的集合对象,以便MVC在表单提交时传递给您的操作方法。新对象(&#34; updatedContents&#34;在此示例中)与在ComplexObject模型中定义和填充的list属性(&#34; contents&#34;,在此示例中)基本相同。
这是一项更多的工作,但确实完成了不需要任何javascript用于回发的目标。一切都可以用标准MVC完成。