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

Dis*_*ile 42 asp.net-mvc display-templates asp.net-mvc-3

我在MVC中有以下模型:

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

    public IEnumerable<ChildModel> Children { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

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

@Html.DisplayFor(m => m.Children)
Run Code Online (Sandbox Code Playgroud)

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

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

@model IEnumerable<ChildModel>

<table>
    <tr>
        <th>Property 1</th>
        <th>Property 2</th>
    </tr>
    ...
</table>
Run Code Online (Sandbox Code Playgroud)

如何创建具有模型类型的显示模板,IEnumerable<ChildModel>然后在@Html.DisplayFor(m => m.Children)没有抱怨模型类型错误的情况下调用?

Dar*_*rov 62

像这样:

@Html.DisplayFor(m => m.Children, "YourTemplateName")
Run Code Online (Sandbox Code Playgroud)

或者像这样:

[UIHint("YourTemplateName")]
public IEnumerable<ChildModel> Children { get; set; }
Run Code Online (Sandbox Code Playgroud)

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

@model IEnumerable<ChildModel>

<table>
    <tr>
        <th>Property 1</th>
        <th>Property 2</th>
    </tr>
    ...
</table>
Run Code Online (Sandbox Code Playgroud)

  • 我不相信这个答案是100%正确的.1)如果使用模板名称调用DisplayFor,它将不会自动迭代收集; 2)在显示模板中指定@model ICollection将不允许在不从集合中检索项目的情况下访问ChildModel属性,即需要使用foreach (5认同)
  • @ Jack0fshad0ws,你是对的.这就是为什么在我的回答中我在模板中使用了`@model IEnumerable <ChildModel>`.因为在指定模板名称时,传递给模板的模型是集合属性. (4认同)
  • 我是否正确理解,没有办法(a)避免foreach和(b)指定模板的名称?在上面的例子中,我仍然需要@foreach通过表行. (3认同)
  • 更正...您将 IEnumerable 的集合传递给您的模板,但您的模板的模型将是单数。MVC 为您的集合中的每个项目重新创建模板一次。 (2认同)

小智 8

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

您可以在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;
    }
Run Code Online (Sandbox Code Playgroud)

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

在模板中,您无法直接访问集合中元素的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 });
}
Run Code Online (Sandbox Code Playgroud)

在我看来,我只是调用@ Html.DisplayForModel()并加载模板.无需在模型上指定"UIHint".

我希望这有一些价值.


Luk*_*ett 8

在我关于不从视图中获取输出的问题中,我实际上有一个如何使用子模型集合模拟模型并将它们全部渲染的示例.

ASP.NET显示模板 - 无输出

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

@model ChildModelCollection 

@foreach (var child in Model)
{
    Html.DisplayFor(m => child);
}
Run Code Online (Sandbox Code Playgroud)

在您的模板中,集合模型用于迭代和渲染子项.每个孩子都需要强类型,因此您可能也想为项目创建自己的模型类型,并为这些项目设置模板.

所以对于OP问题:

public class ChildModelCollection : Collection<ChildModel> { }
Run Code Online (Sandbox Code Playgroud)

将制作一个强类型模型,该模型是一个可以像其他模板一样解析为模板的集合.