
In this recipe, we are going to look at how we can get some reuse out of our display code by using templated helpers.
To continue our e-commerce example, we are going to look at how to control the format of bits of our Product
class from the previous recipe. Specifically, we will take a look at how to centralize the display of our product's cost.
- First, we need to go into the
Views/Home
folder and create a new folder calledDisplayTemplates
. - Next, we need to create a partial view that will hold the display logic for the product's
cost
property. Right-click on theDisplayTemplates
folder in theViews/Home
folder and select Add View. - Name your view
Product.Cost
and then select the Create a partial view (.ascx) checkbox. - Now open up your new partial view and add some code to format the cost of a product (a
Double
). The Model reference in this code will be whatever value you feed this snippet later.Views/Home/DisplayTemplates/Product.Cost.ascx:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %> <%= String.Format("{0:C}", Model)%>
- Now open up your
Product.aspx
view page. Under the place where theProductName
is currently displayed, we will display theCost
property and specify with a hint which template we want to use.Views/Home/Product.aspx:
<p><%= Model.CurrentCategory.Name %></p> <%= Model.CurrentProduct.ProductName %> <%= Html.DisplayFor(Double=>Model.CurrentProduct.Cost, "Product.Cost") %>
- Hit F5 and see your
cost
property formatted appropriately!
The rendering engine noticed your hint of Product.Cost
. It then looked in the DisplayTemplates
folder to see if there were any templates with the same name as the Product.Cost
hint. When it found the Product.Cost.ascx
partial view, the call to Html.DisplayFor
used the partial view to render the property.
Notice that in the DisplayFor
method we used a lambda expression to pass only the Cost
property (a Double
) to the partial view. This is the only sticky part of how these templates work. The caller needs to know what the partial view expects.
There are a few other things to know about templated helpers. Rather than using hints to specify how you want to render things, you could instead build templates based purely on data types. Also, you don't have to put the DisplayTemplates
folder in the Home
view subdirectory. You could instead create a template for usage by a view in any of the view folders. And if you did want to use hints but didn't want to specify them in the presentation code, that can be done too!
Templated helpers, by default, can be based on the data type that is passed into the Html.DisplayFor
method. If you were to create a Double.ascx
partial view and place it in the DisplayTemplates
folder and you then passed in the Cost
property to the DisplayFor
method, it would have worked just as well. Expand this thought to creating a template for the Product
type and this can quickly simplify the creation of a website!
The DisplayTemplates
folder can be in both a specific view folder or in the shared folder. The DisplayFor
method will first look in the current controller's corresponding view folder for any appropriate DisplayTemplates
folder. If it doesn't find an appropriate partial view for the current rendering, it will look to the shared folder for an appropriate display template.
To utilize this method, the mechanics of using the Html.DisplayFor
and the creation of the partial view in a DisplayTemplates
folder are identical as mentioned earlier. The only thing different here is that you would specify a UIHint
attribute on the Product
class like this:
[UIHint("Product.Cost")] public Double Cost { get; set; }
I am not a big fan of this particular method though; I think that it puts concerns in the wrong places (formatting code shouldn't be specified with your business objects). You could use this method on your ViewModel
though, depending on where you specify it.