A grid provides a common presentation to represent a collection of data, which is a table containing rows and columns. Although creating this experience is not difficult, the features to deliver a quality user experience will require a significant investment. The alternative is a widget library, which provides advanced features requiring minimal effort.

In this post, I will demonstrate a few features of the Kendo UI Grid, which is one of many widgets included in the Kendo UI products. After several years of experience with Telerik products, the next generation Kendo UI is HTML5 and CSS3. I also elected to include the Kendo UI Complete, which packages convenient server extensions for the JavaScript framework. You can learn more about the products and better understand the licensing, which is a huge obstacle for many budget conscious organization. And yes…many alternatives exist including the JQuery.UI library.

Kendo UI provides a handy Visual Studio plugin, which can convert and prepare projects for Kendo UI. I converted an existing ASP.NET MVC4 project, which saves several manual steps. I was also able to select one of the Kendo themes, which will be applied to all Kendo widgets.

You can read several of my previous posts, which discuss design patterns to build enterprise applications. In this article, my goal is to provide a quick start for the Kendo UI Grid implementation. So…I will not create a fully functioning repository, but instead a static memory based to provide the basics for the demonstration.

I will modify the standard ASP.NET MVC4 starter project and add a new menu option called Contacts. This will require a controller, view model and service - all the basics. We’ll start with a simple read-only grid, which will display the current contacts with paging, filtering and sorting features. The following is the read-only Contacts grid.

Contacts Read-Only Grid

The grid is a table containing the Name, Mode of Contact, Phone and Email columns. The sort, filter and paging features are enabled, so the user can interact with the grid and data using several helpful options. So…let’s look at the view containing the grid configuration.

 C# |  copy code |? 
01
@using MvcKendoUIGrid.Models
02
 
03
@(Html.Kendo().Grid<Contact>()
04
      .Name("contactGrid")
05
      .Columns(columns =>
06
 
07
          {
08
               columns.Bound(c => c.Name).Title("Name").Width(150);
09
              columns.Bound(c => c.PreferredContactMode).Title("Mode of Contact").Width(150);
10
              columns.Bound(c => c.Phone).Title("Phone").Width(120);
11
              columns.Bound(c => c.Email).Title("Email").Width(120);
12
          })
13
      .Pageable()
14
      .Filterable()
15
      .Sortable()
16
      .Scrollable()
17
      .AutoBind(true)
18
      .HtmlAttributes(new {style = "height:250px;"})
19
      .DataSource(dataSource => dataSource
20
                                    .Ajax()
21
                                    .ServerOperation(false)
22
                                    .Model(model =>
23
                                        {
24
                                            model.Id(c => c.Id);
25
                                            model.Field(c => c.PreferredContactMode).Editable(true).DefaultValue(new ContactMode {Id = 0, Name = string.Empty});
26
                                        })
27
                                    .Read(read => read.Action("Read", "Contact"))
28
)      )

The Pageable, Sortable, Filterable and Scrollable provide the advanced grid features with just one line of code. The DataSource defines the data and actions to read. The model is the Contact, so the fields and id are defined. The Read action is an ajax call to the Contact controller and Read method, which will return a collection of Contact objects. The Columns define the layout of columns, headers and binding to the model.

The Contact model contains the Id, NamePhone and Email properties. It also includes the ContactMode, which is a complex object including an Id and Name. We’ll see more on the complex object in the next section.

 C# |  copy code |? 
01
using System.Collections.Generic;
02
using System.Web.Mvc;
03
using Kendo.Mvc.Extensions;
04
using Kendo.Mvc.UI;
05
using MvcKendoUIGrid.Models;
06
using MvcKendoUIGrid.Services;
07
 
08
namespace MvcKendoUIGrid.Controllers
09
{
10
    /// <summary>
11
    /// Contact controller providing support for views
12
    /// </summary>
13
    public class ContactController : Controller
14
    {
15
        private readonly IContactService _service;
16
 
17
        /// <summary>
18
        /// Default Constructor
19
        /// </summary>
20
        public ContactController()
21
        {
22
            _service = new ContactService();
23
        }
24
 
25
        /// <summary>
26
        /// Default action to render Contact grid
27
        /// </summary>
28
        /// <returns></returns>
29
        public ActionResult Index()
30
        {
31
            TempData["ContactMode"] = new List<ContactMode>
32
                {
33
                    new ContactMode {Id = 1, Name = "Phone"},
34
                    new ContactMode {Id = 2, Name = "Email"}
35
                };
36
 
37
            return View();
38
        }
39
 
40
        /// <summary>
41
        ///     Read action to populate grid
42
        /// </summary>
43
        /// <param name="dsRequest">Kendo Datasource Request</param>
44
        /// <returns>ActionResult</returns>
45
        [HttpPost]
46
        public ActionResult Read([DataSourceRequest] DataSourceRequest dsRequest)
47
        {
48
            try
49
            {
50
                return Json(_service.GetAllContacts().ToDataSourceResult(dsRequest));
51
            }
52
            catch
53
            {
54
                ModelState.AddModelError("Contacts", "Unable to load contacts.");
55
                return Json(ModelState.ToDataSourceResult());
56
            }
57
        }
58

The Index action is called on the initially, which will save the possible ContactMode selections as TempData. The Read action invokes the service GetAllContacts method to return a collection of Contacts.

The next step is providing the ability to edit the contacts. The following is the revised view, which includes the changes to enable editing.

 C# |  copy code |? 
01
@using MvcKendoUIGrid.Models
02
 
03
@(Html.Kendo().Grid<Contact>()
04
      .Name("contactGrid")
05
      .Columns(columns =>
06
 
07
          {
08
              columns.Command(command =>
09
                  {
10
                      command.Edit();
11
                   }).Width(180);
12
              columns.Bound(c => c.Name).Title("Name").Width(150);
13
              columns.Bound(c => c.PreferredContactMode).Title("Mode of Contact").Width(150);
14
              columns.Bound(c => c.Phone).Title("Phone").Width(120);
15
              columns.Bound(c => c.Email).Title("Email").Width(120);
16
          })
17
      .Pageable()
18
      .Filterable()
19
      .Sortable()
20
      .Scrollable()
21
      .AutoBind(true)
22
      .HtmlAttributes(new {style = "height:250px;"})
23
      .Editable(ed => ed.Mode(GridEditMode.InLine))
24
      .DataSource(dataSource => dataSource
25
                                    .Ajax()
26
                                    .ServerOperation(false)
27
                                    .Model(model =>
28
                                        {
29
                                            model.Id(c => c.Id);
30
                                            model.Field(c => c.PreferredContactMode).Editable(true).DefaultValue(new ContactMode {Id = 0, Name = string.Empty});
31
                                        })
32
                                    .Read(read => read.Action("Read", "Contact"))
33
                                    .Update(update => update.Action("Edit", "Contact"))
34
      )
35
      )

The DataSource now includes the Update, which calls the Contact controller Edit method. The Editable supports inline and popup edit modes, so we will select inline to allow editing within the grid. We also add a column command, which injects the edit button in the first column. We also add the Edit method to the controller, which is responsible for calling the service to update the contract.

 C# |  copy code |? 
01
        /// <summary>
02
        /// Edit action to update existing contact
03
        /// </summary>
04
        /// <param name="dsRequest">Kendo Datasource Request</param>
05
        /// <param name="viewmodel">Contact model containing values to update</param>
06
        /// <returns>ActionResult</returns>
07
        [HttpPost]
08
        public ActionResult Edit([DataSourceRequest] DataSourceRequest dsRequest, Contact viewmodel)
09
        {
10
            try
11
            {
12
                if (ModelState.IsValid && viewmodel != null)
13
                    _service.Update(viewmodel);
14
                else //model error
15
                    ModelState.AddModelError("Contacts", "Unable to edit contact - not a valid contact.");
16
            }
17
            catch
18
            {
19
                ModelState.AddModelError("Contacts", "Unable to edit contact.");
20
            }
21
 
22
            return Json(ModelState.ToDataSourceResult());
23
        }
24

If we test the changes then we see the addition of the edit button. Clicking the edit button will allow the editing of the selected row.

Contact Grid Edit

You will notice the Mode of Contact column displays the Id and Name textbox, which is not the best experience for selecting the contact mode.

Contact Grid Edit Complex Object

Since ContactMode is a complex object, the editor includes the Id and Name. We would like to provide a dropdown list of available contact modes, so the user must select a valid option. We previously saved a collection of ContactMode objects representing the valid options in the TempData, so this will be the dropdown list source. The solution is creating a new editor for the ContactMode type, so when the correct editor is presented. The following is the ContactMode editor, which should be added to the Shared Editor Templates folder.

 C# |  copy code |? 
1
@model MvcKendoUIGrid.Models.ContactMode
2
@(Html.Kendo().DropDownList()
3
      .Name("PreferredContactMode")
4
      .BindTo((System.Collections.IEnumerable)TempData["ContactMode"])
5
      .OptionLabel("Select a Mode")
6
      .DataTextField("Name")
7
      .DataValueField("Id")
8
      .HtmlAttributes(new { required = true })
9
      )

We are using the Kendo UI DropDownList widget, which is a dropdown list. The BindTo is the list data source, which is referencing the TempData we populated in our initial Index method. The DataTextField and DataValueField are the value and text property names. We also set the required attribute, which ensures the contact mode is required. It is important to note the Name must be the name of the grid model property, so the two-way binding is correct. Let’s see the results of the changes to the edit mode.

Contacts Grid Edit Dropdown

The final features are Add and Delete. The following is the view containing the updates for Add and Delete. You will also notice the ClientTemplate applied to the ContactMode, which forces the view to include the Name property in the display.

 C# |  copy code |? 
01
@using MvcKendoUIGrid.Models
02
 
03
@(Html.Kendo().Grid<Contact>()
04
      .Name("contactGrid")
05
      .Columns(columns =>
06
 
07
          {
08
              columns.Command(command =>
09
                  {
10
                      command.Edit();
11
                      command.Destroy();
12
                  }).Width(180);
13
              columns.Bound(c => c.Name).Title("Name").Width(150);
14
              columns.Bound(c => c.PreferredContactMode).Title("Mode of Contact").ClientTemplate("#=PreferredContactMode.Name#").Width(150);
15
              columns.Bound(c => c.Phone).Title("Phone").Width(120);
16
              columns.Bound(c => c.Email).Title("Email").Width(120);
17
          })
18
      .ToolBar(toolbar => toolbar.Create().Text("Add new contact"))
19
      .Pageable()
20
      .Filterable()
21
      .Sortable()
22
      .Scrollable()
23
      .AutoBind(true)
24
      .HtmlAttributes(new {style = "height:250px;"})
25
      .Editable(ed => ed.Mode(GridEditMode.InLine))
26
      .DataSource(dataSource => dataSource
27
                                    .Ajax()
28
                                    .ServerOperation(false)
29
                                    .Model(model =>
30
                                        {
31
                                            model.Id(c => c.Id);
32
                                            model.Field(c => c.PreferredContactMode).Editable(true).DefaultValue(new ContactMode {Id = 0, Name = string.Empty});
33
                                        })
34
                                    .Read(read => read.Action("Read", "Contact"))
35
                                    .Update(update => update.Action("Edit", "Contact"))
36
                                    .Destroy(delete => delete.Action("Delete", "Contact"))
37
                                    .Create(create => create.Action("Create", "Contact"))
38
      )
39
      )

We add the Destroy to the command, which provides the Delete button. The DataSource Destroy defines the Contact controller delete action, which will be responsible for deleting the contact. We add the create command to the Toolbar, which is positioned above the grid. The DataSource Create is the action invoked when the “Add new contact” button is clicked.

The Create and Delete controller methods appear below.

 C# |  copy code |? 
01
        /// <summary>
02
        /// Create action to add new contact
03
        /// </summary>
04
        /// <param name="dsRequest">Kendo Datasource Request</param>
05
        /// <param name="viewmodel">Contact model containing values to add</param>
06
        /// <returns>ActionResult</returns>
07
        [HttpPost]
08
        public ActionResult Create([DataSourceRequest] DataSourceRequest dsRequest, Contact viewmodel)
09
        {
10
            try
11
            {
12
                if (ModelState.IsValid && viewmodel != null)
13
                {
14
                    _service.Add(viewmodel);
15
                    return Json(new[] {viewmodel}.ToDataSourceResult(dsRequest, ModelState));
16
                }
17
                ModelState.AddModelError("Contacts", "Unable to add contact - not a valid contact.");
18
            }
19
            catch
20
            {
21
                ModelState.AddModelError("Contacts", "Unable to add contact.");
22
            }
23
 
24
            return Json(ModelState.ToDataSourceResult());
25
        }
26
 
27
        /// <summary>
28
        /// Delete action to remove existing contact
29
        /// </summary>
30
        /// <param name="dsRequest">Kendo Datasource Request</param>
31
        /// <param name="viewmodel">Contact model containing values to delete</param>
32
        /// <returns>ActionResult</returns>
33
        [HttpPost]
34
        public ActionResult Delete([DataSourceRequest] DataSourceRequest dsRequest, Contact viewmodel)
35
        {
36
            try
37
            {
38
                if (viewmodel != null)
39
                    _service.Delete(viewmodel);
40
                else
41
                    ModelState.AddModelError("Contacts", "Unable to delete contact - not a valid contact.");
42
            }
43
            catch
44
            {
45
                ModelState.AddModelError("Contacts", "Unable to delete contact.");
46
            }
47
 
48
            return Json(ModelState.ToDataSourceResult());
49
        }
50

The final version with the Edit, Add and Delete actions enabled.

Contacts Grid Complete

Contacts Grid AddContacts Grid Delete

I hope this provides a quick overview of the Kendo UI Grid widget and Kendo UI MVC server extensions, which together provide powerful features with minimal effort.