简体   繁体   中英

EditorFor ICollection and named Template

i am new to MVC 5 and ASP.NET, EF6 and now i have a Problem with a named EditorTemplate.

My Model looks like this:

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; }
}

And i have a EditorTemplate called FiltersCustomEditor, thats look like this:

@model IList<Filter>

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

My Problem is now that in my Product View i can´t call:

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

I get this error:

The model element that has been passed to the dictionary , is of type "System.Collections.Generic.HashSet 1[Filter]". However, this dictionary requires a model item of type "System.Collections.Generic.IList 1[Filter]". However, this dictionary requires a model item of type "System.Collections.Generic.IList 1[Filter]".]

So i tried to call it like this:

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

And get this error:

Templates can only be used with field access , property access , one-dimensional array indices or custom Indexerausdrücken with a single parameter .

If i convert the ICollection in my Model to a List it works perfect. But this is a generated class from Entity Framework so a change here breaks the EF functionality.

I think this is a special problem for named Templates. Because if i make a Default EditorTemplate for a Single Filter called Filter.cshtml and calling

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

The ICollection is handled internaly very well and the EditorFor calls the Template for each Object in the List.

But their must be a solution for this Problem. The Only thing that works is to change the Template to

@model ICollection<Filter>

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

And call it like this

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

But i think this is realy a weak solution, specialy for performance, if every field must convert the ICollection to a List before access.

So is their a way to workaround or am i missing something?

Your passing ICollection<Filter> to the template, but the model in the template is IList<Filter> , hence the error ( ICollection<T> is not IList<T> ). However your approach is not correct. The EditorFor() method accepts IEnumerable<T> so the code can be simplified to

In /Views/Shared/EditorTemplates/Filter.cshtml (note the template must be named the same as the name of the class)

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

and then in the main view it is simply

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

The EditorFor() method will correctly generate the html for each item in your collection based on the template (no loops, no passing collections etc.)

Side note: Further to you comments, you can also place specific EditorTemplates related to each controller in the /Views/YourControllerName/EditorTemplates folder. By default, the EditorFor() method will first search /Views/YourController/EditorTemplates . If one is not found it will then search /Views/Shared/EditorTemplates . And finally if one is not found it will use the built in default template(s) based on your model properties.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM