MVC Html.DisplayFor for Lists of Derived Models

我的梦境 提交于 2021-01-28 05:31:37

问题


Let's assume that I have three classes: Derived1ViewModel, Derived2ViewModel and BaseViewModel which serves as a superclass for the Derived1ViewModel and Derived2ViewModel.

I have a DisplayTemplate which has as a model a List<BaseViewModel> and I would like to call this template from views which are using as a model a List<Derived1ViewModel> or a List< Derived2ViewModel>.

If I try to do this, an exception is triggered saying that it cannot convert a List<Derived1ViewModel> or List<Derived2VIewModel> to a List<BaseViewModel>. If I try to apply a cast such as @Html.DisplayFor(model=>model.Cast<BaseViewModel>.ToList(), "MyTemplate") an InvalidOperationException is thrown.

Details: [InvalidOperationException: Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.]

Can this problem be solved or its necessary to take another approach?


回答1:


Note that in @Html.DisplayFor(model=>model, "MyTemplate") the first parameter is not the Model. It is an Expression that will be evaluated on the Model.

The Model is implicitly passed to the MVC Expression Compiler (using ViewData i think) and that Model's type will still be what you declare at the start of the Razor page. It has nothing to with the expression. The Expression just indicates what data is needed with the model as the starting parameter.

having said that, give this a shot:

@Html.DisplayFor(model=>model.Select(dm=>(BaseViewModel)dm).ToList(), "MyTemplate")

although i have a feeling that you might hit the MVC Expression Evaluation snag, where it can handle only a particular set of Expressions. (Constant Expression, Member access etc.)

we can come to that based on your results.




回答2:


If your model is subclass of IEnumerble<SomeModel>

MVC Will render it as SomeModel,

First, you cant cast List<A> to List<B> directly

So either convert to List<B> in view and use Display( instead of DisplayFor or change the model type of your display template from List<A> to IEnumerable<A>

Second,You have to set template name in UIHintAttribute or pass it as parameter to DisplayFor




回答3:


Solved the problem by using a template for BaseViewModel instead of List<BaseViewModel>. In this way, I can pass any derived type to the template (ex: Derived1ViewModel, Derived2ViewModel).

Example:

@*Derived1 View*@
@model List<Derived1ViewModel>
@for(var i = 0; i < Model.Count; i++)
{
    int i1 = i;
    @Html.DisplayFor(model=>model[i1], "MyTemplate")
}

@*Derived2 View*@
@model List<Derived2ViewModel>
@for(var i = 0; i < Model.Count; i++)
{
    int i1 = i;
    @Html.DisplayFor(model=>model[i1], "MyTemplate")
}

@*Template*@
@model BaseViewModel
<p>It works @Model.Name</p>


来源:https://stackoverflow.com/questions/23000679/mvc-html-displayfor-for-lists-of-derived-models

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!