我有一个示例asp.net mvc5程序,其中我尝试构建一个支付模型,其中添加了许多级别的部分以创建完整的对象。在这个例子中,我使用的是通用数据。我有一个顶级'测试',你可以添加多个' A1'对象,你可以添加多个' B2'对象。
表单使用ajax和jquery来允许此人动态添加数据,然后在按下提交按钮时立即提交数据。
我找到了由html helper 制作的Matt Lunn作为editorForMany。它运作良好,将我的所有信息添加到网页,但它永远不会回发深度超过2级的模型(顶部,附加a1')。
我可以在我的页面上构建整个模型。它看起来很合适,但是当我回发时,A1下面没有任何东西显示出来。我可以根据需要添加尽可能多的A1。如果我更改了代码并直接对测试进行了测试,那么这样就行了,但是没有任何内容可以像我一样添加在 这是我的代码。我为这篇文章的格式和长度道歉。 MVC助手 测试控制器 模型类 startTest.cshtml EditorTemplates
(测试编辑器模板) (a1编辑模板) (b2编辑模板) addA1.cshtml addB2.cshtml 好的,我很抱歉格式化。我对这里的格式有点新意。我必须手动缩进我的代码才能显示在代码块中。 public static MvcHtmlString EditorForMany<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, IEnumerable<TValue>>> propertyExpression, Expression<Func<TValue, string>> indexResolverExpression = null, bool includeIndexField = true) where TModel : class
{
var items = propertyExpression.Compile()(html.ViewData.Model);
var htmlBuilder = new StringBuilder();
var htmlFieldName = ExpressionHelper.GetExpressionText(propertyExpression);
var htmlFieldNameWithPrefix = html.ViewData.TemplateInfo.GetFullHtmlFieldName(htmlFieldName);
Func<TValue, string> indexResolver = null;
if (indexResolverExpression == null)
{
indexResolver = x => null;
}
else
{
indexResolver = indexResolverExpression.Compile();
}
foreach (var item in items)
{
var dummy = new { Item = item };
var guid = indexResolver(item);
var memberExp = Expression.MakeMemberAccess(Expression.Constant(dummy), dummy.GetType().GetProperty("Item"));
var singleItemExp = Expression.Lambda<Func<TModel, TValue>>(memberExp, propertyExpression.Parameters);
if (String.IsNullOrEmpty(guid))
{
guid = Guid.NewGuid().ToString();
}
else
{
guid = html.AttributeEncode(guid);
}
if (includeIndexField)
{
htmlBuilder.Append(_EditorForManyIndexField<TValue>(htmlFieldNameWithPrefix, guid, indexResolverExpression));
}
htmlBuilder.Append(html.EditorFor(singleItemExp, null, String.Format("{0}[{1}]", htmlFieldName, guid)));
}
MvcHtmlString m1 = new MvcHtmlString(htmlBuilder.ToString());
return m1;
}
public class testingController : Controller
{
// GET: testing
public ActionResult startTest()
{
var model = new testing();
return View(model);
}
[HttpPost]
public ActionResult startTest([Bind] testing model)
{
if (ModelState.IsValid)
{
var r = 1;
}
return View(model);
}
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
public ActionResult addA1()//current running test
{
var model = new testing();
model.aas.Add(new A1());
return View(model);
}
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
public ActionResult addB2()//current running test
{
var model = new A1();
model.bbs.Add(new B2());
return View(model);
}
}
public class testing
{
public string name { get; set; }
public List<A1> aas { get; set; }
public testing()
{
aas = new List<A1>();
}
}
public class A1
{
public string aName { get; set; }
public List<B2> bbs { get; set; }
public A1()
{
bbs = new List<B2>();
}
}
public class B2
{
public string bName { get; set; }
public B2() { }
}
@model proofOfConceptPaymentBuilder.Models.testing
@{
ViewBag.Title = "startTest";
}
@section Scripts
{
<script>
jQuery(document).ready(function ($) {
$('#add-bbs').on('click', function () {
jQuery.get('/testing/addB2').done(function (html) {
$('#bbsList').append(html);
});
});
$('#add-aas').on('click', function () {
jQuery.get('/testing/addA1').done(function (html) {
$('#aasList').append(html);
});
});
});
function alertSomething() {
alert('something');
jQuery.get('/testing/addB2').done(function (html) {
$('#bbsList').append(html);
});
};
</script>
}
@using (Html.BeginForm())
{
<h2>Create</h2>
@Html.EditorFor(x => x)
<input type="submit" />
}
@model proofOfConceptPaymentBuilder.Models.testing
<div class="form-group">
@Html.LabelFor(x => x.name)
@Html.EditorFor(x => x.name)
</div>
<div class="form-group">
<div id="aasList">
@Html.EditorFor(x => x.aas)
</div>
<input type="button" id="add-aas" value="add aas" />
<input type="button" id="delete-testing" value="delete test" />
</div>
@model proofOfConceptPaymentBuilder.Models.A1
<div class="form-group">
@Html.LabelFor(x => x.aName)
@Html.EditorFor(x => x.aName)
</div>
<div class="form-group">
<div id="bbsList">
@Html.EditorForMany(x => x.bbs)
</div>
<input type="button" id="add-bbs" value="add bss" onclick="alertSomething()"/>
<input type="button" id="delete-aas" value="delete ass" />
</div>
@model proofOfConceptPaymentBuilder.Models.B2
<div class="form-group">
@Html.LabelFor(x => x.bName)
@Html.EditorFor(x => x.bName)
</div>
<div>
<input type="button" id="delete-bss" value="delete bbs" />
</div>
@model proofOfConceptPaymentBuilder.Models.testing
@{
Layout = null;
}
@Html.EditorForMany(x => x.aas)
@model proofOfConceptPaymentBuilder.Models.A1
@{
Layout = null;
}
@Html.EditorForMany(x => x.bbs)
答案 0 :(得分:0)
我也偶然发现了这个问题,考虑到我在StackOverflow上发现的类似问题,我创建了一个.NET Core库来解决这个问题。它称为DynamicVML (Dynamic View-Model Lists),您可以使用NuGet来获取它。
基本上,它是ASP.NET Core的列表模板引擎,可用于显示任何深度的视图模型列表。
您可以像这样使用它:
@Html.ListEditorFor(x => x.Addresses,
Url.Action("AddAddress"), // the action in your controller that creates views
"Add new address", // some text for the "add new item button" in your form
listContainerTemplate: "viewThatWrapsTheList",
listTemplate: "viewForTheList",
itemContainerTemplate: "viewThatWrapsYourViewModel",
ItemTemplate: "viewForYourViewModel")
现在,您实际上不必指定所有这些内容。如果您愿意,您可以只是
@Html.ListEditorFor(x => x.Addresses, Url.Action("AddAddress"), "Add new address")
它将猜测其余的所有内容。
它是问题的核心,它将支持任何深度的嵌套。