EditorFor IEnumerable with TemplateName

假设我有一个简单的模型来解释目的:

public class Category { ... public IEnumerable Products { get; set; } } 

视图:

 @model Category ... 
    @Html.EditorFor(m => m.Products)

EditorTemplate:

 @model Product ... 
  • @Html.EditorFor(m => m.Name)
  • 请注意,我不必为IEnumerable定义EditorTemplate,我只能为Product模型创建它,而MVC框架足够智能,可以使用自己的IEnumerable模板。 它遍历我的集合并调用我的EditorTemplate。

    输出html将是这样的

     ... 
  • 毕竟,我可以发布到我的控制器。

    但是,当我使用模板名称定义EditorTemplate时,为什么MVC没有做到这一点?

     @Html.EditorFor(m => m.Products, "ProductTemplate") 

    在这种情况下,我必须将属性的类型更改为IList ,自己遍历集合并调用EditorTemplate

     @for (int i = 0; i  m.Products[i], "ProductTemplate") } 

    这似乎是一种肮脏的解决方法给我。 这样做是否还有其他更清洁的解决方案?

    这样做是否还有其他更清洁的解决方案?

    简单的答案是否定的,它很糟糕,我完全同意你的意见,但这就是框架设计者决定实现这一function的方式。

    所以我所做的就是坚持惯例。 由于我有每个视图和局部视图的特定视图模型,因此使用相应的编辑器模板并不是什么大问题,其命名方式与集合的类型相同。

    在那里,现在我只欠Darin 9999啤酒。

      public static MvcHtmlString EditorForMany(this HtmlHelper html, Expression>> expression, string templateName = null) where TModel : class { StringBuilder sb = new StringBuilder(); // Get the items from ViewData var items = expression.Compile()(html.ViewData.Model); var fieldName = ExpressionHelper.GetExpressionText(expression); var htmlFieldPrefix = html.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix; var fullHtmlFieldPrefix = String.IsNullOrEmpty(htmlFieldPrefix) ? fieldName : String.Format("{0}.{1}", htmlFieldPrefix, fieldName); int index = 0; foreach (TValue item in items) { // Much gratitude to Matt Hidinger for getting the singleItemExpression. // Current html.DisplayFor() throws exception if the expression is anything that isn't a "MemberAccessExpression" // So we have to trick it and place the item into a dummy wrapper and access the item through a Property var dummy = new { Item = item }; // Get the actual item by accessing the "Item" property from our dummy class var memberExpression = Expression.MakeMemberAccess(Expression.Constant(dummy), dummy.GetType().GetProperty("Item")); // Create a lambda expression passing the MemberExpression to access the "Item" property and the expression params var singleItemExpression = Expression.Lambda>(memberExpression, expression.Parameters); // Now when the form collection is submitted, the default model binder will be able to bind it exactly as it was. var itemFieldName = String.Format("{0}[{1}]", fullHtmlFieldPrefix, index++); string singleItemHtml = html.EditorFor(singleItemExpression, templateName, itemFieldName).ToString(); sb.AppendFormat(singleItemHtml); } return new MvcHtmlString(sb.ToString()); }