One very interesting addition to MVC 2 is the power to assign templates to fields in your classes and make the rendering suit your needs. The advantage is that, if you need to display the same field in several views, you can benefit from a one-stop place where you can customize its display and have all views automatically updating based on it.

Let’s take a look at this model that will be used to render my view:

public class Author

{

    public string Name { get; set; }

    public string Email { get; set; }

    public string Avatar { get; set; }

}

 

public class Post

{

    public string Title { get; set; }

    public string Body { get; set; }

    public string Rating { get; set; }

    public DateTime Date { get; set; }

    public Author AuthorInfo { get; set; }

}


Let’s implement a simple action method to test our view:

public ActionResult Index()

{

    Author author = new Author();

    author.Name = "Nuno Silva";

    author.Email = "nunos@microsoft.com";

    author.Avatar = "http://a1.twimg.com/profile_images/673101428/nunosilva_bigger.jpg";

    author.Active = false;       

 

    Post post = new Post();

    post.Title = "ASP.NET Quick Tip #1";

    post.Body = "Some awesome tip";

    post.Date = System.DateTime.Now;

    post.Rating = "Excellent";

    post.AuthorInfo = author;

   

    return View("Index",post);

}


If you use Visual Studio to add a strongly-typed view for the Post class, using the Details template you will get something similar to this:

<h2>Index</h2>

 

<fieldset>

    <legend>Post Information</legend>

    <p>

        Title:

        <%= Html.Encode(Model.Title) %>

    </p>

    <p>

        Body:

        <%= Html.Encode(Model.Body) %>

    </p>

    <p>

        Rating:

        <%= Html.Encode(Model.Rating) %>

    </p>

    <p>

        Date:

        <%= Html.Encode(String.Format("{0:g}", Model.Date)) %>

    </p>

</fieldset>

<fieldset>

    <legend>Author</legend>

    <p>

        Name:

        <%= Html.Encode(Model.AuthorInfo.Name) %>

    </p>

    <p>

        Email:

        <%= Html.Encode(Model.AuthorInfo.Email) %>

    </p>

    <p>

        Avatar:

        <%= Html.Encode(Model.AuthorInfo.Avatar) %>

    </p>

    <p>

        Active:

        <%= Html.Encode(Model.AuthorInfo.Active) %>

    </p>

</fieldset>

 


Note: the second fieldset was added manually to display the Author information aswell.

Executing the application you will get the following output:

default rendering

All the properties we are rendering, apart from Date and Active are simple strings. The default templates that Visual Studio provides to generate your views will render the strings using Html.Encode when in display view, and using a Textbox when in edit mode.

However, MVC 2 introduced the concept of templates that is very tied to the workings of Dynamic Data. The engine includes a set of templates for each type of field and you can extend that either by changing the default rendering of property types or by adding your own.

Let’s change the view and instead of hardcoding the rendering, we’ll use the strongly typed Html helpers introduced in MVC 2:

<h2>Index</h2>

<fieldset>

    <legend>Post Information</legend>

    <p>

        Title:

        <%= Html.DisplayFor(model => model.Title) %>

    </p>

    <p>

        Body:

        <%= Html.DisplayFor(model => model.Body) %>

    </p>

    <p>

        Rating:

        <%= Html.DisplayFor(model => model.Rating) %>

    </p>

    <p>

        Date:

        <%= Html.DisplayFor(model => model.Date) %>

    </p>

</fieldset>

<fieldset>

    <legend>Author</legend>

    <p>

        Name:

        <%= Html.DisplayFor(model => model.AuthorInfo.Name) %>

    </p>

    <p>

        Email:

        <%= Html.DisplayFor(model => model.AuthorInfo.Email) %>

    </p>

    <p>

        Avatar:

        <%= Html.DisplayFor(model => model.AuthorInfo.Avatar) %>

    </p>

    <p>

        Active:

        <%= Html.DisplayFor(model => model.AuthorInfo.Active) %>

    </p>

</fieldset>


Notice we are using the DisplayFor helper which has the possibility of additionally specifying a template name as the second parameter. There is also a EditorFor helper for edit views.

If you now launch the website, you will notice that nothing changed apart from one important detail:

rendering with checkbox for boolean

Notice how the rendering for the Active field changed to a Checkbox. How did that happen? Well, the DisplayFor helper actually uses the notion of templates to render the information. Because this is a Boolean field, it displays a checkbox instead of rendering it as a string.

The good news is that you can either change or extend this behavior to suit your own needs. This is a powerful feature where you can have predefined templates for your data and have all the views correctly displaying the information the way you want it to.

If you take a look at the display, you see that the Date is displaying both date and time information. Let’s say we only want to display the date part throughout the application. Sure, you could go into your view and use a format string to tailor it this way, but you’d have to do it for every view where you display date information. So, the best option is to create a template for it.

In your Solution Explorer, add a folder under the Views for the Home Controller and call it DisplayTemplates:

solution explorer

Inside that folder, add a view, make sure you choose the partial view checkbox and call it DateTime:

Adding a partial view

This will create a Partial View (a feature we will cover further in a later Quick Tip). It’s very similar to the notion of User Controls in ASP.NET Web Forms. Change the code of the view to this:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>

<%= Html.Encode(String.Format("{0:d}", Model)) %>

 

Now, simply start your application again. Notice how the date format changed:

Date formatted

So, what happened here was: the DisplayFor helper noticed we had created a template for DateTime, so it chose to use our template instead of the default rendering. That means we can override the rendering that ASP.NET MVC provides for our fields. But that won’t be enough in some cases right?

Take a look at the Email field. Sure, it’s displaying the email address. But what if we want to make this into a link, so we allow people to send an email message just by clicking on it? The problem is that it’s simply a string, and we can’t just override the default string rendering in our entire application.

Fortunately, there are a couple of ways around it. One is using the second parameter of the DisplayFor helper, that allows us to specify a template for rendering.

Create a second partial view called Email and use the following code:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>

<a href="mailto:<%= Html.Encode(Model) %>"><%= Html.Encode(Model) %></a>


Now change the view so that the email field looks like this:

<p>

    Email:

    <%= Html.DisplayFor(model => model.AuthorInfo.Email,"Email") %>

</p>


Start your application, the output will look like this:

Email field formatted as link

So, pretty cool, we were able to extend this with our custom template. However, I don’t like the fact that I have to specify the template name in the DisplayFor helper. I would like to do it in a centralized location, so I don’t have to go in each view and add that information.

Fortunately, we can, using Data Annotations (another concept of Dynamic Data). Let’s try to use this approach to have a better display for the Avatar.

Create a new partial view called Avatar and use the following code:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>

<img src="<%= Html.Encode(Model) %>" />

 

Now, instead of specifying the template in the view, let’s go over to our model definition and add one “small” detail:

[UIHint("Avatar")]

public string Avatar { get; set; }


We’re basically adding information on the model itself, specifying which template to use to render this field. Launching the application, you should now see this:

Avatar displayed as picture

Because I chose the template on the model definition, all views that display the Avatar information will use my template, provided they use the DisplayFor helper. This means that I can later change my template, or chose another one and have all views updating automatically.

I will show in a later tip how to add templates for edit more (using the EditorFor) and how to use the Data Annotations feature to add custom validation to my model.

Until then, have fun!