简体   繁体   English

具有嵌套模型类的Razor视图

[英]Razor view with nested model class

I have a nested class such as : 我有一个嵌套类,如:

public class Jar
{
    public IEnumerable<NailClippings> Nails { set; get; }
    public IEnumerable<People> Donors { set; get; }
}

My controller passes a single Jar to my view, string typed as 我的控制器将一个Jar传递给我的视图,字符串键入为

@model Test.ViewModels.Jar

I can loop through the contents of Nails and Donors easily with something like this 我可以通过这样的东西轻松地遍历NailsDonors的内容

@foreach(var item in Model.Nails)

My issue is with using HTML helpers to generate Display names for me 我的问题是使用HTML帮助程序为我生成显示名称

@Html.DisplayNameFor(model => model.Nails.Length)

I have come up with a solution by changing the type of the inner nested classes to List , appending .ToList() at the end of my queries and changing the line to 我通过将内部嵌套类的类型更改为List ,在查询结束时附加.ToList()并将行更改为

@Html.DisplayNameFor(model => model.Nails[0].Length)

Being forced to use List and have an index [0] to display a name is goofy to me. 被迫使用List并使用索引[0]来显示名称对我来说太愚蠢了。 Is there an alternative method for referencing inner nested class attributes? 是否有另一种引用内部嵌套类属性的方法?

Edit : View 编辑 :查看

<table>
    <tr>
        <th>@Html.DisplayNameFor(model => model.Nails[0].Length)</th>
        .
        .
    </tr>
    @foreach(var item in Model.Nails){
    <tr>
        <td>@Html.DisplayFor(modelItem => item.Length</td>
        .
        .
    </tr>
    }
</table>

You don't need to be writing any loops in your views. 您不需要在视图中编写任何循环。 It makes them so ugly. 这让他们变得如此丑陋。

Simply define a corresponding display template for the collection type. 只需为集合类型定义相应的显示模板即可。 So for example you would create ~/Views/Shared/DisplayTemplates/NailClippings.cshtml partial view that will be strongly typed to a single element of the collection: 因此,例如,您将创建~/Views/Shared/DisplayTemplates/NailClippings.cshtml部分视图,该视图将强烈类型~/Views/Shared/DisplayTemplates/NailClippings.cshtml集合的单个元素:

@model NailClippings
<tr>
    <td>
        @Html.DisplayFor(x => x.Length)
    </td>
    .
    .
</tr>

and now inside your main view it's as simple as: 现在在主视图中,它很简单:

@model Jar
<table>
    <thead>
        <tr>
            <th>Length</th>
            .
            .
        </tr>
    </thead>
    <tbody>
        @Html.DisplayFor(x => x.Nails)
    </tbody>
</table>

Display/editor templates work by convention. 显示/编辑器模板按惯例工作。 So here when inside your main view you use @Html.DisplayFor(x => x.Nails) , ASP.NET MVC will analyze the type of the Nails property and will see that it is an IEnumerable<NailClippings> collection. 因此,当您在主视图中使用@Html.DisplayFor(x => x.Nails) ,ASP.NET MVC将分析Nails属性的类型,并将看到它是一个IEnumerable<NailClippings>集合。 So it will start looking for a corresponding display template first inside ~/Views/CurrentController/DisplayTemplates/NailClippings.cshtml , then inside ~/Views/Shared/DisplayTemplates/NailClippings.cshtml and finally it will fallback to the default display template . 因此它将首先在~/Views/CurrentController/DisplayTemplates/NailClippings.cshtml内部开始寻找相应的显示模板,然后在~/Views/Shared/DisplayTemplates/NailClippings.cshtml ,最后它将回~/Views/Shared/DisplayTemplates/NailClippings.cshtml default display template When a template is selected this template will automatically be executed for you by ASP.NET MVC for each element of the collection property so that you never have to worry about things like writing some loops in your views, worry about indexes, ... 当选择模板时,ASP.NET MVC将为集合属性的每个元素自动为您执行此模板,这样您就不必担心在视图中编写一些循环,担心索引,......

This also works with editor templates: @Html.EditorFor(x => x.Nails) will look for ~/Views/Shared/EditorTemplates/NailClippings.cshtml . 这也适用于编辑器模板: @Html.EditorFor(x => x.Nails)将查找~/Views/Shared/EditorTemplates/NailClippings.cshtml The bonus you get here is that the generated input fields will have correct names and you when you submit the form, the default model binder will automatically rehydrate your view model that the HttpPost action is taking as argument from the request. 您获得的奖励是生成的输入字段将具有正确的名称,并且当您提交表单时,默认模型绑定器将自动为您的视图模型重新水化HttpPost操作作为请求的参数。

Basically if you respect the conventions that the framework is following you will make your life much easier. 基本上,如果您尊重框架遵循的惯例,您将使您的生活更轻松。

Instead of 代替

model.Nails[0].Length

You could use 你可以用

model.Nails.First().Length

Without having to convert to a List . 无需转换为List

I think you can just use item variable of loop 我想你可以只使用循环的item变量

@Html.DisplayNameFor(model => item.Length)

UPDATE another option for you is creating partial view for Nails displaying. 更新另一个选项是为Nails显示创建局部视图。 It will be strongly typed to IEnumerable<NailClippings> and all properties will be available: 它将被强类型IEnumerable<NailClippings>并且所有属性都可用:

@Html.Partial("_Nails", Model.Nails)

Nails partial view: 指甲局部视图:

@model IEnumerable<NailClippings>

<table>
    <tr>
        <th>@Html.DisplayNameFor(model => model.Length)</th>
        .
        .
    </tr>
    @foreach(var item in Model){
    <tr>
        <td>@Html.DisplayFor(modelItem => item.Length)</td>
        .
        .
    </tr>
    }
</table>

I think this sample code is useful for nested model class 我认为这个示例代码对嵌套模型类很有用

@model ViewModels.MyViewModels.Theme

@Html.LabelFor(Model.Theme.name)
@foreach (var category in Model.Theme)
{
   @Html.LabelFor(category.name)
   @foreach(var product in theme.Products)
   {
      @Html.LabelFor(product.name)
      @foreach(var order in product.Orders)
      {
          @Html.TextBoxFor(order.Quantity)
          @Html.TextAreaFor(order.Note)
          @Html.EditorFor(order.DateRequestedDeliveryFor)
      }
   }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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