Telerik blogs

If you are a .NET developer, ASP.NET MVC gives you full access to the rendering of your data as HTML. This is often seen as a virtue over ASP.NET WebForms where so much of the rendering is controlled by the server and wrapped up in the page life cycle. Both WebForms and MVC have their place on the web though. In this article, we're going to look at how you can create controls in ASP.NET MVC to display your model values based on their type.

Display Templates

ASP.NET MVC 2 brought with it the ability to create something called DisplayTemplates and EditorTemplates. Templating has been around for a long time in web development, and the idea is simply that you have a re-usable control that you can plug your model values into, and it gives you the markup you need to either display or edit that model value.

Let's look at this in action. If you create a new View and use the List scaffold, you will see ASP.NET MVC using the DisplayFor method to render the fields. In this case we are rendering a collection of Resources from a small database into an HTML table.

@model IEnumerable<editor_template_demo.Models.Resource>

@{
  ViewBag.Title = "List";
}

<h2>List</h2>

<p>
  @Html.ActionLink("Create New", "Create")
</p>
<table>
  <tr>
    <th>
      @Html.DisplayNameFor(model => model.ResourceName)
    </th>
    <th>
      @Html.DisplayNameFor(model => model.ResourceType)
    </th>
    <th>
      @Html.DisplayNameFor(model => model.Color)
    </th>
    <th></th>
  </tr>

@foreach (var item in Model) {
  <tr>
    <td>
      @Html.DisplayFor(modelItem => item.ResourceName)
    </td>
    <td>
      @Html.DisplayFor(modelItem => item.ResourceType.ResourceTypeName)
    </td>
    <td>
      @Html.DisplayFor(modelItem => item.Color)
    </td>
    <td>
      @Html.ActionLink("Edit", "Edit", new { id=item.ResourceID }) |
      @Html.ActionLink("Details", "Details", new { id=item.ResourceID }) |
      @Html.ActionLink("Delete", "Delete", new { id=item.ResourceID })
    </td>
  </tr>
}

</table>

The "Color" field for each resource is actually a hex color. Instead of displaying the text, we would really like to display the color. We could do that by putting the HTML in the view, but it would be better if we created a re-usable partial view that would render this HTML anytime the Color field on the model was rendered in a view.

DisplayTemplates solve this problem.

For instance, for the Color, we could create a DisplayTemplate that looks like this...

Color.cshtml

<div class="circle" style="background-color: @Model"></div>

This creates a <div> element and sets its background color to whatever model value is passed in. I also added a simple circle class to give this div a set size and make it into a circle with a 50% border radius. This degrades nicely into a simply square in older version of IE (8-) that don't support the CSS border-radius.

Site.css

.circle {
  border-radius: 50%;
  width: 25px;
  height: 25px; 
  margin: auto;
}

This Color.cshtml file gets placed in a "DisplayTemplates" folder inside the View folder for the controller (i.e. View/Home for HomeController). It is then accessible by all views in that folder. If you want it accessible by all views in the application (which you usually do), you create a "DisplayTemplates" folder in the "Shared" folder.

The next step is to tell ASP.NET MVC that we want it to use this specific DisplayTemplate when it renders the "Color" field on the model. To do this, we use the [UIHint("Color")] property decoration. This tells ASP.NET MVC that you want to use a DispayTemplate called "Color" for this field.

Resource.cs

namespace editor_template_demo.Models {
  public class Resource {
    public int ResourceID { get; set; }
    public string ResourceName { get; set; }

    [UIHint("Color")]
    public string Color { get; set; }

    public ResourceType ResourceType { get; set; }
  }
}

Now the view renders our circle div with the hex model value as the background color.

DisplayTemplates give you great code re-use in your UI, and since they are actually rendered depending on the model property type or UIHint decoration, you can keep your code really DRY.

EditorTemplates solve the same problem when you want to provide an editing surface for a model or model value.

EditorTemplates

We can create an edit form using the MVC scaffolding, and we'll get a page that looks like this...

Take a look at the markup that ASP.NET MVC generates for you when you choose an edit scaffold.

Edit.cshtml

@model editor_template_demo.Models.Resource

@{
  ViewBag.Title = "Edit";
}

<h2>Edit</h2>

@using (Html.BeginForm()) {
  @Html.AntiForgeryToken()
  @Html.ValidationSummary(true)

  <fieldset>
    <legend>Resource</legend>

    @Html.HiddenFor(model => model.ResourceID)

    <div class="editor-label">
      @Html.LabelFor(model => model.ResourceName)
    </div>
    <div class="editor-field">
      @Html.EditorFor(model => model.ResourceName)
      @Html.ValidationMessageFor(model => model.ResourceName)
    </div>

    <div class="editor-label">
      @Html.LabelFor(model => model.Color)
    </div>
    <div class="editor-field">
      @Html.EditorFor(model => model.Color)
      @Html.ValidationMessageFor(model => model.Color)
    </div>

    <p>
      <input type="submit" value="Save" />
    </p>
  </fieldset>
}

<div>
  @Html.ActionLink("Back to List", "Index")
</div>

Notice that instead of DisplayFor, we are now using the EditorFor HTML helpers. They do the same thing, but load a partial view from the "EditorTemplates" folder instead of the "DisplayTemplates" folder.

The DisplayTemplates are loaded with DisplayFor and the EditorTemplates are loaded with EditorFor.

Adding A ColorPicker Editor Template

Obviously we don't want a free form text field for our color. That would be a pain to validate, and I'm pretty sure not many people have the hexadecimal color scheme memorized. We need a color picker here. We could us the HTML5 color input type, but it's still in draft and has really flaky support across browsers. To get a robust control with support for as many browsers as possible, I'm going to use a Kendo UI ColorPicker.

If you created your project using the Kendo UI ASP.NET MVC project templates, you already have what you need. If you didn't, read this article on how to add the DLL to your project and appropriate Web.Config entries. Remember to close your page and then reopen it after you add the DLL so that Razor will pick up the Kendo UI HTML Helpers.

We're going to create an "EditorTemplates" folder under "Shared" just like we did for the DisplayTemplates. Inside, we'll create a "Color.cshtml" partial view. Kendo UI actually exposes it's widgets with a For method for composing editor templates which are loaded by EditorFor.

Color.cshtml

@model string

@Html.Kendo().ColorPickerFor(m => m)

Editor Templates use the UIHint property decoration as well, so now every time MVC sees a model field with a UIHint of color, EditorFor will generate a Kendo UI Color Picker.

Kendo UI Grid And Templates

There is no faster way to build rich HTML5 applications than with Kendo UI for ASP.NET MVC. I've written about the virtues of the wrappers before. From static type checking, to automatic AJAX request/response configuration, to dynamic LINQ query helpers; the MVC wrappers for Kendo UI have you covered from the client, all the way through to the database.

One of the most popular controls in the Kendo UI ASP.NET MVC suite is the Grid. This isn't surprising since the core UI component of many applications is an interactive grid. Grids are incredibly easy to setup with Kendo UI for ASP.NET MVC.

We could take the multi-page ASP.NET MVC flow we created for the Resource collection and use a Kendo UI Grid to create a powerful single-page editing surface.

The Kendo UI Grid has two "flows" when it comes to editing. The Server Flow and the Ajax Flow. They are both quite similar, but have a few subtle differences that you should be aware of.

Kendo UI Grid Server Flow

The server flow configures the grid so that any actions that occur in the grid cause a "postback" (for lack of a better word) to the server.

In this example, the grid is setup for inline editing using a command column. The command columns automatically generate buttons which put the grid into edit, create or delete mode without you having to wire up any client code at all.

Index.cshtml

@model IEnumerable<editor_template_demo.Models.Resource>

@{
  ViewBag.Title = "Index";
}

@(Html.Kendo().Grid(Model)

  // all kendo ui widgets must have a name
  .Name("Resources")

  // custom column configuration...
  .Columns(c => {

    c.Command(p => p.Edit()).Width(176);

    // db columns with custom titles/widths
    c.Bound(p => p.ResourceName);
    c.Bound(p => p.ResourceType.ResourceTypeName).Width(220);

    // specify a custom template for the color column
    c.Bound(p => p.Color).Width(100);

    c.Command(p => p.Destroy()).Width(100);
  })

  .Editable(e => e.Mode(GridEditMode.InLine))
  .DataSource(d => d
    .Server()
    .Model(m => {
      m.Id("ResourceID");
    })
    .Update("Update", "Home")
    .Destroy("Destroy", "Home")
  )

  .HtmlAttributes(new { style= "width: 800px" })

)

Note: When using server rendering, the grid must have a fixed width and all but one column should have a specified width

Notice that we automatically get the Color DisplayTemplate? That's because Kendo UI uses DisplayFor when you are using Server Flow (which designated by the Server() method on the DataSource definition).

We also get the ColorPicker EditorTemplate when the grid goes into edit mode. No surprises there!

Kendo UI Default Editor Templates

If you created your project from the Kendo UI for ASP.NET MVC template, you will have the option in the wizard to copy in some EditorTemplates. These simply provide default Kendo UI styling and controls for most common input types. For instance, if you have a DateTime model field, Kendo UI will look for the Date.cshtml editor template which renders a Kendo UI DatePicker for you.

Handling More Complex Templates

You may have noticed through this article that there is one input type in the model that I have so far been dodging, and that's the ResourceType.

The ResourceType field is a property on the Resource model that is really an object. This is because in the database, Resource and ResourceType are two separate tables that are joined on ResourceTypeID. This sort of "foreign key" structure is a common model for databases. It presents a challenge on the UI though, which wants to display the data in one flattened structure.

We can solve this with the a ForeignKey Column.

Foreign Key Columns

We can use the ForeignKey column type in the Kendo UI Grid configuration. We have to pass a SelectList from our controller first, which will hold all of the available ResourceTypes.

HomeController.cs

public ActionResult Index() {

  ViewBag.Message = "Welcome to ASP.NET MVC!";

  // returns a collection of Resource.cs models
  var resources = getResources();

  // returns a collection of ResourceType.cs models
  var resourceTypes = getResourceTypes();

  // pass a new select list of the resource types specifying the text and value fields.
  ViewBag.ResourceType_Data = new SelectList(resourceTypes, "ResourceTypeID", "ResourceTypeName");

  // send the model objects to the view
  return View(resources);
}

Then we create a new ForeignKey column definition. Notice that it wants the ID of the select item as it's model. The SelectList from the ViewData is used as the data for the Kendo UI DropDownList. I don't have to declare the DataTextField or DataValueField because I did that in the ResourceTypes SelectList on the controller.

Index.cshtml

@model IEnumerable<editor_template_demo.Models.Resource>

@{
  ViewBag.Title = "Index";
}

@(Html.Kendo().Grid(Model)

  // all kendo ui widgets must have a name
  .Name("Resources")

  // custom column configuration...
  .Columns(c => {

    c.Command(p => p.Edit()).Width(176);

    // db columns with custom titles/widths
    c.Bound(p => p.ResourceName);

    // use a grid foreign key column to display a dropdown list of resource types
    // in edit mode
    c.ForeignKey("ResourceType.ResourceTypeID", (SelectList)ViewData["ResourceTypes"])
      .Title("Resource Type").Width(200);

    // specify a custom template for the color column
    c.Bound(p => p.Color).Width(100);

    c.Command(p => p.Destroy()).Width(100);
  })

  .Editable(e => e.Mode(GridEditMode.InLine))
  .DataSource(d => d
    .Server()
    .Model(m => {
      m.Id("ResourceID");
    })
    .Update("Update", "Home")
    .Destroy("Destroy", "Home")
  )

  .HtmlAttributes(new { style= "width: 800px" })

)

AJAX Mode

AJAX is part of the magic of the web. Why make a roundtrip when we can just perform actions via Ajax? We simply toggle the "Server()" method to "Ajax()" in the DataSource, and tell Kendo UI that we are not using ServerOperations.

OH NO! What happened to our nice colored circle? Those nasty hex values are back. This is because in Ajax mode, the grid doesn't use the DisplayFor method to build the grid. This is because we could be getting our initial data from the model, or from a JSON Ajax call. Instead, it uses a Kendo UI ClientTemplate.

Index.cshtml

@model IEnumerable<editor_template_demo.Models.Resource>

@{
    ViewBag.Title = "Index";
}

@(Html.Kendo().Grid(Model)

  // all kendo ui widgets must have a name
  .Name("Resources")

  // custom column configuration...
  .Columns(c => {

      c.Command(p => p.Edit()).Width(176);

      // db columns with custom titles/widths
      c.Bound(p => p.ResourceName);

      // use a grid foreign key column to display a dropdown list of resource types
      // in edit mode
      c.ForeignKey("ResourceType.ResourceTypeID", (SelectList)ViewData["ResourceTypes"])
          .Title("Resource Type").Width(200);

      // specify a custom template for the color column
      c.Bound(p => p.Color).Width(100).ClientTemplate("<div class='circle' style='background-color: #: Color #'></div>");

      c.Command(p => p.Destroy()).Width(100);
  })

  .Editable(e => e.Mode(GridEditMode.InLine))
  .DataSource(d => d
      .Ajax()
      .ServerOperation(false)
      .Model(m => {
          m.Id("ResourceID");
      })
      .Update("Update", "Home")
      .Destroy("Destroy", "Home")
  )
)

The EditorTemplate still works in AJAX mode, so there are no changes needed there. This takes care of displaying custom templates in both display and edit mode in the grid when the edit mode is inline. If we switch the edit mode to Popup, you will see that we lost some of our customizations.


PopUp Mode displays a window and uses the EditorForModel ASP.NET method to create the controls for each of the model fields. Normally, this works just fine. However in the case of the Resource Model, the ResourceType is an object and therefor EditorForModel doesn't map it to a control. Even with a UIHint. If we had a ResourceTypeID instead of a complex ResourceType object, we could decorate that model value with [UIHint("GridForeignKey")] and everything would work just fine. As it is, we need to create a custom Popup Editor.

Custom PopUp Editors

Simply create a new partial view in the "EditorTemplates" folder. Inside, add the markup to display all of the fields using EditorTemplates. Since we have access to the model, we can specify that we want an editor for ResourceType.ResourceTypeID.

Resource.cshtml

@model editor_template_demo.Models.Resource

@Html.HiddenFor(model => model.ResourceID)

<div class="editor-label">
  @Html.LabelFor(model => model.ResourceName)
</div>
<div class="editor-field">
  @Html.EditorFor(model => model.ResourceName)
  @Html.ValidationMessageFor(model => model.ResourceName)
</div>

<div class="editor-label">
  @Html.LabelFor(model => model.ResourceType)
</div>
<div class="editor-field">
  @Html.EditorFor(model => model.ResourceType.ResourceTypeID)
</div>

<div class="editor-label">
  @Html.LabelFor(model => model.Color)
</div>
<div class="editor-field">
  @Html.EditorFor(model => model.Color)
</div>

This code renders the ResourceTypeID as TextBox. To get a DropDownList, we just need to decorate the ResourceTypeID field on the Resource model with [UIHint("GridForeignKey")].

ResourceType.cs

namespace editor_template_demo.Models {
  public class ResourceType {

    [UIHint("GridForeignKey")]
    public int ResourceTypeID { get; set; }

    public string ResourceTypeName { get; set; }
  }
}

If it feels awkward to you to have "GridForeignKey" on your model object, I don't blame you. Another (possibly better) option is to just specify the name of the editor you want to use in the Popup Editor template.

Resource.cshtml

@model editor_template_demo.Models.Resource

@Html.HiddenFor(model => model.ResourceID)

<div class="editor-label">
  @Html.LabelFor(model => model.ResourceName)
</div>
<div class="editor-field">
  @Html.EditorFor(model => model.ResourceName)
  @Html.ValidationMessageFor(model => model.ResourceName)
</div>

<div class="editor-label">
  @Html.LabelFor(model => model.ResourceType)
</div>
<div class="editor-field">
  <!-- specify the GridForeignKey editor for this field -->
  @Html.EditorFor(model => model.ResourceType.ResourceTypeID, "GridForeignKey")
</div>

<div class="editor-label">
  @Html.LabelFor(model => model.Color)
</div>
<div class="editor-field">
  @Html.EditorFor(model => model.Color)
</div>

Once you understand how EditorTemplates and DisplayTemplates work, its much easier to understand how Kendo UI uses them to provide the editing interface. Kendo UI builds on top of standard MVC conventions to bring you the next generation of web apps today, while giving you the full power of the .NET framework. Grab a free download of Kendo UI for ASP.NET MVC today and take your ASP.NET skills to the next level.

I also encourage you to checkout the comprehensive code library full of Kendo UI for ASP.NET MVC sample Visual Studio projects that provide simple and concise examples for all of the most frequently asked questions on the Kendo UI Grid and other widgets.


Burke Holland is the Director of Developer Relations at Telerik
About the Author

Burke Holland

Burke Holland is a web developer living in Nashville, TN and was the Director of Developer Relations at Progress. He enjoys working with and meeting developers who are building mobile apps with jQuery / HTML5 and loves to hack on social API's. Burke worked for Progress as a Developer Advocate focusing on Kendo UI.

Related Posts

Comments

Comments are disabled in preview mode.