asp.net-mvc ASP.net MVC - 集合的显示模板

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8002059/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 01:34:16  来源:igfitidea点击:

ASP.net MVC - Display Template for a collection

asp.net-mvcasp.net-mvc-3display-templates

提问by Dismissile

I have the following model in MVC:

我在MVC中有以下模型:

public class ParentModel
{
    public string Property1 { get; set; }
    public string Property2 { get; set; }

    public IEnumerable<ChildModel> Children { get; set; }
}

When I want to display all of the children for the parent model I can do:

当我想显示父模型的所有孩子时,我可以这样做:

@Html.DisplayFor(m => m.Children)

I can then create a ChildModel.cshtml display template and the DisplayFor will automatically iterate over the list.

然后我可以创建一个 ChildModel.cshtml 显示模板,DisplayFor 将自动遍历列表。

What if I want to create a custom template for IEnumerable?

如果我想为 IEnumerable 创建自定义模板怎么办?

@model IEnumerable<ChildModel>

<table>
    <tr>
        <th>Property 1</th>
        <th>Property 2</th>
    </tr>
    ...
</table>

How can I create a Display Template that has a model type of IEnumerable<ChildModel>and then call @Html.DisplayFor(m => m.Children)without it complaining about the model type being wrong?

如何创建一个模型类型为 的显示模板,IEnumerable<ChildModel>然后调用@Html.DisplayFor(m => m.Children)而不抱怨模型类型错误?

回答by Darin Dimitrov

Like this:

像这样:

@Html.DisplayFor(m => m.Children, "YourTemplateName")

or like this:

或者像这样:

[UIHint("YourTemplateName")]
public IEnumerable<ChildModel> Children { get; set; }

where obviously you would have ~/Views/Shared/DisplayTemplates/YourTemplateName.cshtml:

显然你会有~/Views/Shared/DisplayTemplates/YourTemplateName.cshtml

@model IEnumerable<ChildModel>

<table>
    <tr>
        <th>Property 1</th>
        <th>Property 2</th>
    </tr>
    ...
</table>

回答by swazza85

This is in reply to Maslow's comment. This is my first ever contribution to SO, so I don't have enough reputation to comment - hence the reply as an answer.

这是对马斯洛评论的回复。这是我对 SO 的第一次贡献,所以我没有足够的声誉来发表评论 - 因此回复作为答案。

You can set the 'TemplateHint' property in the ModelMetadataProvider. This would auto hookup any IEnumerable to a template you specify. I just tried it in my project. Code below -

您可以在 ModelMetadataProvider 中设置“TemplateHint”属性。这会将任何 IEnumerable 自动连接到您指定的模板。我刚刚在我的项目中尝试过。下面的代码 -

protected override CachedDataAnnotationsModelMetadata CreateMetadataFromPrototype(CachedDataAnnotationsModelMetadata prototype, Func<object> modelAccessor)
    {
        var metaData = base.CreateMetadataFromPrototype(prototype, modelAccessor);
        var type = metaData.ModelType;

        if (type.IsEnum)
        {
            metaData.TemplateHint = "Enum";
        }
        else if (type.IsAssignableFrom(typeof(IEnumerable<object>)))
        {
            metaData.TemplateHint = "Collection";
        }

        return metaData;
    }

You basically override the 'CreateMetadataFromPrototype' method of the 'CachedDataAnnotationsModelMetadataProvider' and register your derived type as the preferred ModelMetadataProvider.

您基本上覆盖了“CachedDataAnnotationsModelMetadataProvider”的“CreateMetadataFromPrototype”方法,并将您的派生类型注册为首选的ModelMetadataProvider。

In your template, you cannot directly access the ModelMetadata of the elements in your collection. I used the following code to access the ModelMetadata for the elements in my collection -

在您的模板中,您不能直接访问集合中元素的 ModelMetadata。我使用以下代码访问集合中元素的 ModelMetadata -

@model IEnumerable<object>
@{ 
var modelType = Model.GetType().GenericTypeArguments[0];
var modelMetaData = ModelMetadataProviders.Current.GetMetadataForType(null, modelType.UnderlyingSystemType);

var propertiesToShow = modelMetaData.Properties.Where(p => p.ShowForDisplay);
var propertiesOfModel = modelType.GetProperties();

var tableData = propertiesOfModel.Zip(propertiesToShow, (columnName, columnValue) => new { columnName.Name, columnValue.PropertyName });
}

In my view, I simply call @Html.DisplayForModel() and the template gets loaded. There is no need to specify 'UIHint' on models.

在我看来,我只需调用 @Html.DisplayForModel() 即可加载模板。无需在模型上指定“UIHint”。

I hope this was of some value.

我希望这有一定的价值。

回答by Luke Puplett

In my question about not getting output from views, I actually have an example of how to template a model with a collection of child models and have them all render.

在我关于不从视图中获取输出的问题中,我实际上有一个示例,说明如何使用一组子模型对模型进行模板化并让它们全部呈现。

ASP.NET Display Templates - No output

ASP.NET 显示模板 - 无输出

Essentially, you need to create a model that subclasses List<T>or Collection<T>and use this:

本质上,您需要创建一个子类List<T>Collection<T>使用它的模型:

@model ChildModelCollection 

@foreach (var child in Model)
{
    Html.DisplayFor(m => child);
}

In your template for the collection model to iterate and render the children. Each child needs to strongly-typed, so you may want to create your own model types for the items, too, and have templates for those.

在您的集合模型模板中迭代和呈现子项。每个子项都需要强类型,因此您可能还想为项目创建自己的模型类型,并为这些项目创建模板。

So for the OP question:

所以对于 OP 问题:

public class ChildModelCollection : Collection<ChildModel> { }

Will make a strongly-typed model that's a collection that can be resolved to a template like any other.

将创建一个强类型模型,该模型是一个可以像任何其他模板一样解析为模板的集合。

回答by SandRock

The actual "valid answer" is -IMHO- not correctly answering the question. I think the OP is searching for a way to have a list template that triggers without specifying the UIHint.

实际的“有效答案”是 - 恕我直言 - 没有正确回答问题。我认为 OP 正在寻找一种方法来拥有一个无需指定 UIHint 即可触发的列表模板。

Magic stuff almost does the job

神奇的东西几乎可以完成工作

Some magic loads the correct view for a specified type.
Some more magic loads the same viewfor a collection ofa specified type.
There shouldbe some magic that iterates the same view for a collection of a specified type.

一些魔法为指定的类型加载正确的视图。
更多的魔法为指定类型的集合加载相同的视图。 这里应该有一些神奇的是遍历一个指定类型的集合同样的观点。

Change the actual behavior?

改变实际行为?

Open your favorite disassembler. The magic occurs in System.Web.Mvc.Html.TemplateHelpers.ExecuteTemplate. As you can see, there are no extensibility points to change the behavior. Maybe a pull request to MVC can help...

打开您最喜欢的反汇编程序。魔法发生在System.Web.Mvc.Html.TemplateHelpers.ExecuteTemplate. 如您所见,没有可扩展点来更改行为。也许对 MVC 的拉取请求可以帮助...

Go with the actual magic

使用真正的魔法

I came up with something that works. Create a display template ~/Views/Shared/DisplayTemplates/MyModel.cshtml.

我想出了一些有效的方法。创建显示模板~/Views/Shared/DisplayTemplates/MyModel.cshtml

Declare the model as type object.

将模型声明为 type object

If the object is a collection, iterate and render the template again. If it's not a collection, then show the object.

如果对象是一个集合,则迭代并再次渲染模板。如果它不是一个集合,则显示该对象。

@model object

@if (Model is IList<MyModel>)
{
    var models = (IList<MyModel>)Model;
<ul>
    @foreach (var item in models)
    {
@Html.Partial("DisplayTemplates/MyModel", item)
    }
</ul>
} else {
    var item = (MyModel)Model;
    <li>@item.Name</li>
    }
}

Now DisplayForworks without UIHint.

现在DisplayFor无需UIHint.