【问题标题】:EditorFor ICollection and named TemplateEditorFor ICollection 和命名模板
【发布时间】:2015-07-23 12:14:51
【问题描述】:

我是 MVC 5 和 ASP.NET、EF6 的新手,现在我遇到了一个名为 EditorTemplate 的问题。

我的模型如下所示:

public partial class Product
{
    public int pid { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Filter> Filters{ get; set; }
}

public partial class Filter
{
    public bool isRemoveable { get; set; }
}

我有一个名为 FiltersCustomEditor 的 EditorTemplate,看起来像这样:

@model IList<Filter>

@Html.EditorFor(modelItem => @Model[i].isRemoveable)

我现在的问题是在我的产品视图中我无法调用:

@Html.EditorFor(m => m.Filters, "FiltersCustomEditor")

我收到此错误:

已传递给字典的模型元素的类型为“System.Collections.Generic.HashSet1[Filter]". However, this dictionary requires a model item of type "System.Collections.Generic.IList1[Filter]”。]

所以我试着这样称呼它:

@Html.EditorFor(m => m.Filters.ToList(), "FiltersCustomEditor")

并得到这个错误:

模板只能与字段访问、属性访问、一维数组索引或带有单个参数的自定义 Indexerausdrücken 一起使用。

如果我将模型中的 ICollection 转换为列表,它会完美运行。但这是从 Entity Framework 生成的类,因此此处的更改会破坏 EF 功能。

我认为这是命名模板的一个特殊问题。因为如果我为名为 Filter.cshtml 的单个过滤器创建默认 EditorTemplate 并调用

@Html.EditorFor(m => m.Filters)

ICollection 在内部得到很好的处理,EditorFor 为列表中的每个对象调用模板。

但是他们必须是这个问题的解决方案。唯一可行的是将模板更改为

@model ICollection<Filter>

@Html.EditorFor(modelItem => @Model.ToList()[i].isRemoveable)

然后这样称呼它

 @Html.EditorFor(m => m.Filters, "FiltersCustomEditor")

但我认为这确实是一个弱解决方案,特别是性能方面,如果每个字段都必须在访问之前将 ICollection 转换为 List。

那么他们是一种解决方法还是我错过了什么?

【问题讨论】:

  • 您的属性是ICollection&lt;Filter&gt;,但您的视图是@model IList&lt;Filter&gt;。它们不是同一件事。您需要更改其中之一。但正确的方法是将您的模板命名为/Views/Shared/EditorTemplates/Filter.cshtml 并使用@Html.EditorFor(m =&gt; m.Filters),其中模板为@model Filter 并包含EditorFor(m =&gt;m.isRemoveable)
  • 是的,这行得通,但是如果我想要一个过滤器列表的自定义编辑器怎么办?特别是如果我想要多个过滤器编辑器?有没有办法将 EditorFor ICollection 的 linq 表达式作为列表给出?
  • 对不起,我不明白您的评论 - 如果模板被命名为与模型匹配并且有 @model Filter@EditorFor(m =&gt;m.isRemoveable) 那么它一个模板,可以用于呈现集合(通过在主视图中使用@Html.EditorFor(m =&gt; m.Filters))。这就是编辑器模板的设计方式。如果您想要多个过滤器,您可以在 Views/YourController/EditorTemplates/Filter.cshtm 添加更具体的过滤器,以便您可以为每个控制器使用不同的模板
  • 不,你不能将 ICollection&lt;T&gt; 传递给期望 IList&lt;T&gt; 的东西,反之亦然
  • 啊,这是一个很好的观点:Views/YourController/EditorTemplates/Filter.cshtm。我不知道每个控制器都有 EditorTemplates,我认为它们必须始终共享。然后使用单元素模板的方法适合我的需要。非常感谢

标签: c# asp.net-mvc templates editorfor icollection


【解决方案1】:

您将ICollection&lt;Filter&gt; 传递给模板,但模板中的模型是IList&lt;Filter&gt;,因此出现错误(ICollection&lt;T&gt; 不是IList&lt;T&gt;)。但是,您的方法不正确。 EditorFor() 方法接受IEnumerable&lt;T&gt; 所以代码可以简化为

/Views/Shared/EditorTemplates/Filter.cshtml中(注意模板名称必须与类名相同)

@model yourAssembly.Filter
@Html.CheckBoxFor(m => m.isRemoveable)
.... // add any other properties, labels etc of Filter

然后在主视图中它只是

@model yourAssembly.Product
@using (Html.BeginForm())
{
  ....
  @Html.EditorFor(m => m.Filters)
}

EditorFor() 方法将根据模板为集合中的每个项目正确生成 html(无循环、无传递集合等)

旁注:除了 cmets,您还可以将与每个控制器相关的特定 EditorTemplates 放在 /Views/YourControllerName/EditorTemplates 文件夹中。默认情况下,EditorFor() 方法将首先搜索/Views/YourController/EditorTemplates。如果没有找到,它将搜索/Views/Shared/EditorTemplates。最后,如果找不到,它将根据您的模型属性使用内置的默认模板。

【讨论】:

    猜你喜欢
    • 2011-08-14
    • 2014-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多