Dynamic Header names in the default ASP.NET MVC List Template

In asp.net mvc when you add a view to  correspond with an action method, you have the option of using several pre-defined templates that come with asp.net mvc (Create, Edit, Delete, Details and List.) Depending on the selected template, a particular view is scaffolded for you containing all the markup needed to perform the action. In this post I’m going to discuss the List template and show you how you can get away from the static header that gets generated by default and instead get the name of property from the DisplayName data annotation attribute.

Assuming you have a simple entity object called Products and it looks something like this:

public class Product{
        public int ProductId { get; set; }

        [DisplayName("Product Name")]
        public string Name { get; set; }
    }

Notice how the “Name” property has a display name attribute attached to it. When generating a List template, I expect the column header to be Product Name.

Let’s go ahead and build an action method like so:

        public ActionResult Index(){
            var products = new List(){
                new Product{ProductId=0,Name="Windows Phone 7"}
            };
            return View(products);
        }

It’s a basic action method that creates a fake list of products and sends it to the view. I’m deliberately keeping the action simple and free of any data access code.

Now add a view to for this action method by right clicking on the method and selecting “Add New View”. Add a strongly typed view of type Product and select the List template.

Look at the resulting markup. In particular, look at the first row of the html table (the header row). It should look something like this:

<table>
  <tr>
     <th></th>
     <th>
       Name
     </th>
   </tr>

Instead of getting “Product Name”, the output of the List template was the name of the property. That’s not what we want! So how do we fix this?

It’s actually a pretty easy change. All we have to do is remove the hard-coded static name and instead use the LabelFor html helper.

Change the markup in the view to the following

    @Html.LabelFor(p=>Model.FirstOrDefault().Name)

Since the header row is outside of our foreach loop, we have use the Model property and get the first item in the collection. For a bit of clarification, we are using a lambda that takes in a paramter p. However, we are not using that parameter since in this case we want to reference the first item in our list collection (via the Model property.)

Now open the page in your browser and you’ll see that the header row has the value “Product Name” instead of name since it’s now pulling the name from data annotations instead of just using the property name.

Now that’s great and what we want. But if we have a big website, we’re going to have to make this change for every list View we scaffold out. It would be nice if we can just modify the template so that any new list views automatically use this new syntax. Fortunately we can do that! Scott Hanselman has a great blog post on modifying the default mvc templates.

Follow the instructions on that page and add the Code Templates folder to your asp.net mvc site. After that go into the cshtml folder and open the list.tt file.

Go to line 70 which should be:

<#= property.Name #>

Change that line to include the new LabelFor html helper like so:

@Html.LabelFor(p=>Model.FirstOrDefault().<#= property.Name #>)

Now anytime you create a new list view it will automatically use the LabelFor syntax instead of hard-coding in just the name. I highly recommend you do this before starting a new project as it will make developing the asp.net mvc site much easier.

5 thoughts on “Dynamic Header names in the default ASP.NET MVC List Template

  1. One small drawback to this method is that it wraps the header text with label tags. You could try this instead:

    @Html.Encode(ModelMetadataProviders.Current.GetMetadataForProperty(null, Model.GetType().GetGenericArguments()[0], “Name”).DisplayName)

  2. Actually, let me revise that. Instead of using the DisplayName property, use the GetDisplayName method. It falls back gracefully to the PropertyName is DisplayName is null. Like this:

    @Html.Encode(ModelMetadataProviders.Current.GetMetadataForProperty(null, Model.GetType().GetGenericArguments()[0], “Name”).GetDisplayName())

Leave a comment