1

This is for an ASP.NET MVC 4 application in a Razor view. I am passing a model to a partial view and am trying to iterate through a given list of properties contained in the model to be displayed as a table.

Given something like List<string> propertyNames, in this table, I would like to output the DisplayNameFor and the value of the property in a structure like so:

<tr>
    <th>@Html.DisplayNameFor(Model.property)</th>
    <td>@Model.property</td>
</tr>

I'll have to do this a few times in the partial because different properties correspond to different div elements in the partial where different tables will be inserted so I've created a helper and this is where I get hung up. First, the only way I know how to do this is reflection, and I have read that reflection is expensive especially for just doing one property at a time. Also, using this method, I can't get @Html.DisplayNameFor to work correctly because, using reflection, I don't quite know the syntax:

@helper IterateDetailPropertyNames(List<string> propertyNames) { 
    foreach (var property in propertyNames)
    {
        <tr>
            <th>
                @Html.DisplayNameFor(m => m.GetType().GetProperty(property).GetValue(Model, null));
                @*Error: Templates can be used only with field access, property access...*@
            </th>
            <td>
                @Model.GetType().GetProperty(property).GetValue(Model, null)
            </td>
        </tr>
    }
}

How can I make this work and improve this?

4
  • Have you tried @Html.DisplayNameFor(m => m[property]); no reflection involved... Commented Nov 16, 2017 at 2:45
  • If your view is using a model, then you can use the ModelMetadata to access all the properties of the model, including its display name. Are you just wanting to display each properties display name and the property value in a table? Commented Nov 16, 2017 at 2:45
  • @StephenMuecke Yes. That's pretty much the gist of it. Commented Nov 16, 2017 at 2:48
  • Then using the models ModelMetadata is the way to go. No time just now, but I'll add answer in 30 min or so. In the meantime, you might be interested in this project - have not go around to writing the docs yet, but that is described here Commented Nov 16, 2017 at 2:51

1 Answer 1

3

A models ModelMetadata gives you the data you need to generate your table. It contains the model value in additional to properties such as the DisplayName, DisplayFormatString, NullDisplayText etc that are determined from annotations applied to your properties.

For more information of ModelMetadata, refer the documentation and ASP.NET MVC 2 Templates, Part 2: ModelMetadata.

To generate your table, you could write the following HtmlHelper extension method

public static class TableHelper
{

    public static MvcHtmlString DisplayTableFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression)
    {
        // Get the ModelMetadata for the model
        ModelMetadata metaData = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);
        StringBuilder html = new StringBuilder();
        // Loop through the ModelMetadata of each property in the model
        foreach (ModelMetadata property in metaData.Properties)
        {
            var x = metaData.DisplayFormatString;
            string label = property.DisplayName;
            string value = null;
            if (property.Model == null)
            {
                value = metaData.NullDisplayText;
            }
            else if (metaData.DisplayFormatString != null)
            {
                value = string.Format(metaData.DisplayFormatString, property.Model);
            }
            else
            {
                value = property.Model.ToString();
            }
            TagBuilder labelCell = new TagBuilder("td");
            labelCell.InnerHtml = label;
            TagBuilder valueCell = new TagBuilder("td");
            valueCell.InnerHtml = value;
            StringBuilder innerHtml = new StringBuilder();
            innerHtml.Append(labelCell.ToString());
            innerHtml.Append(valueCell.ToString());
            TagBuilder row = new TagBuilder("tr");
            row.InnerHtml = innerHtml.ToString();
            html.Append(row.ToString());
        }
        TagBuilder table = new TagBuilder("table");
        table.InnerHtml = html.ToString();
        return new MvcHtmlString(table.ToString());
    }
}

and in the view

@using YourAssembly.TableHelper
....
@Html.DisplayTableFor(m => m)

You can also include the assembly in your web.config file so that the @using statement is not required in the view

As s side note, <table> elements are for tabular data and should not be used for layout. Instead consider using styled <div> elements

Sign up to request clarification or add additional context in comments.

1 Comment

This got me really close so I really appreciate it. That's some pretty useful knowledge for the future too.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.