LyraLearn AI Learning Platform
Exams
← Module 4 Β· Kendo UI for MVC
🎧 Listen

The Grid β€” Your Workhorse

In most agency applications, 80% of your Kendo work is the Grid. Case lists, permit queues, payment histories β€” it's grids all the way down. Master its anatomy once and every screen after that is configuration, not invention.

Anatomy of a grid definition

A typical Razor definition binds the grid to a view model row type (never an EF entity) and wires an AJAX data source:

@(Html.Kendo().Grid<PermitRowVm>()
    .Name("permitsGrid")
    .Columns(c => { c.Bound(p => p.Number); c.Bound(p => p.Status); })
    .Pageable().Sortable().Filterable()
    .DataSource(ds => ds.Ajax().PageSize(25)
        .Read(r => r.Action("Permits_Read", "Permits"))))

.Name() matters: it becomes the element id and the key you use from JavaScript ($("#permitsGrid").data("kendoGrid")). Columns support formatting (.Format("{0:d}")), widths, and client templates for links and badges. Paging, sorting, and filtering are opt-in β€” turn them on and the grid renders the UI, but where the work happens is the next decision.

Server vs client operations

With server operations (the default for Ajax() data sources), every page change or filter triggers a request, and the server returns only one page of data. With .ServerOperation(false), the first read returns everything and the browser pages and filters in memory. The rule of thumb: server operations for anything that can grow (thousands of rows β€” let SQL Server do the work), client operations only for small, stable lists where instant filtering feels snappy and one query is cheaper than many.

ToDataSourceResult β€” the server half

The read action is where Kendo meets Entity Framework. The [DataSourceRequest] binder deserializes the grid's paging/sorting/filter state, and ToDataSourceResult applies it to your IQueryable:

public ActionResult Permits_Read([DataSourceRequest] DataSourceRequest request)
{
    var rows = _db.Permits.Select(p => new PermitRowVm { Number = p.Number, Status = p.Status.Name });
    return Json(rows.ToDataSourceResult(request));
}

Because rows is still an IQueryable, the filter and page are translated into SQL β€” the database returns 25 rows, not 250,000. This is the single most important pattern in the whole library: project to a view model first, keep it IQueryable, then call ToDataSourceResult last. Call .ToList() too early and you've loaded the entire table into memory to page it.

The result JSON carries Data, Total, and any model-state Errors β€” the grid consumes that shape automatically. When a grid "loads forever," check the browser's network tab first: nine times out of ten the read action threw, returned a login redirect, or serialized a cycle because someone returned entities instead of a projection.

🧠 Quiz yourself on this lesson →

Ask the AI Tutor

Grounded in the course lessons β€” it cites its sources and says when it doesn't know.