In this recipe, we will take a look at how we go about creating custom templated helpers for our own types. This is very similar to the previous recipe—in this one we will specify how the template should display our type. But this is different from the previous recipe—we have to tell the view engine how to bind the model of our type to the template; there is just a bit more overhead in this recipe.
Person
class with a few more basic properties. In addition, we're going to decorate some of the properties with an attribute from the System.ComponentModel namespace
.Models/Person.cs:
public class Person using System; using System.ComponentModel; namespace ComplexApplications.Models { public class Person { [DisplayName("First Name")] public string FirstName { get; set; } [DisplayName("Middle Name")] public string MiddleName { get; set; } [DisplayName("Last Name")] public string LastName { get; set; } [DisplayName("Birth Date")] public DateTime BirthDate { get; set; } public string Email { get; set; } public string Phone { get; set; } } }
Person
type will be available when we go to add a strongly typed view. HomeController
so that we can add a new action. Name this action AddPerson
and configure it to return a new instance of Person
. Then create a second action similar to the first. Set this action to accept a Person
as a parameter and to be accessible only via a form post.Controllers/HomeController.cs:
[HttpPost] public ActionResult AddPerson(Person person) { return View(person); } public ActionResult AddPerson() { return View(new Person()); }
AddPerson
actions and select Add View. Configure this view so that it is strongly typed based on a Person
. Also set the content of this view to be an Edit view. div
tags, HTML helpers, and so on. In their place, put an Html.EditorForModel
(which is interchangeable with Html.EditorFor(m=>m)
) to represent the Person
that will be passed into the view. Also provide a button to submit the form.Views/Home/AddPerson.ascx:
<% using (Html.BeginForm()) {%> <%: Html.ValidationSummary(true) %> <%= Html.EditorForModel() %> <input type="submit" value="Add Person" /> <% } %>
Birthdate
field (from the first recipe). Also notice that the labels for each property are responding to the DisplayNameAttribute
that we set earlier. EditorTemplates
folder (Views/Shared
folder), create a partial view called Person.ascx
. Person
partial view, feel free to go crazy with the way you want to represent the Edit controls for a person. To save time, I simply copied the fieldset from the generated view as a starting point. I also switched the BirthDate TextBoxFor
for an EditorFor
helper and removed the Submit button.
Keep in mind: A TextBoxFor
helper is explicitly saying "I want a textbox". An EditorFor
helper will at worst give you a textbox, but will look for better alternatives (such as our DateTime
template) first.
Views/Shared/EditorTemplates:
... <div class="editor-label"> <%: Html.LabelFor(model => model.FirstName) %> </div> <div class="editor-field"> <%: Html.TextBoxFor(model => model.FirstName) %> <%: Html.ValidationMessageFor(model => model.FirstName) %> </div> <div class="editor-label"> <%: Html.LabelFor(model => model.LastName) %> </div> <div class="editor-field"> <%: Html.TextBoxFor(model => model.LastName) %> <%: Html.ValidationMessageFor(model => model.LastName) %> </div> ...
Person
input form.This is very similar to the previous recipe, in that we are building on top of a feature that is provided for us by the framework. We can build up all sorts of different reusable partial views to represent standard types in the .NET framework, as well as our own custom types.
We have been discussing only about creating forms for data input to this point. Of course, the good folks on the MVC team have also provided us with facilities for specifying how we want to display our types. Instead of creating an EditorTemplates
folder, create a DisplayTemplates
folder. Everything works the same from that point on!