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
ASP.net MVC - Display Template for a collection
提问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
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.

