I just finished a rather painful journey into putting together a demo to be able to use the Telerik Grid on a Razor page at all and then how to add checkboxes to it. Sounds easy, but it was not. Just try to find useful (or in some cases any) documentation on this stuff.
Start with the https://github.com/telerik/ui-for-aspnet-core-examples solution and use the Kendo.Examples.RazorPages project. I added a Mange folder under pages and a "Lab" page under that (Lab.cshtml / Lab.cshtml.cs) - here is the code and my discussion follows:
using System;using System.Collections.Generic;using System.Linq;using System.Text.Json;using Kendo.Mvc.Extensions;using Kendo.Mvc.UI;using Microsoft.AspNetCore.Mvc;using Microsoft.AspNetCore.Mvc.RazorPages;namespace Kendo.Examples.RazorPages.Pages.Manage{ public class LabModel : PageModel { public static IList<ClientDto2> ClientsDtos; [TempData] public string TempMessage { get; set; } public bool ShowTempMessage => !string.IsNullOrWhiteSpace(TempMessage); public void OnGet() { Console.WriteLine("Manage OnGet"); try { if (ClientsDtos != null) return; ClientsDtos = new List<ClientDto2>(); //var json = await GetClientJson().ConfigureAwait(false); // substitute test data var json = "[{\"id\": 1,\"clientId\": \"client1\",\"clientName\": \"Client Credentials 1\",\"description\": \"Credentials 1\",\"userCodeType\": \"1\"}," + "{\"id\": 2,\"clientId\": \"client2\",\"clientName\": \"Client Credentials 2\",\"description\": \"Credentials 2\",\"userCodeType\": \"2\"}]"; var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; var clientList = JsonSerializer.Deserialize<List<ClientDto2>>(json, options); foreach (var client in clientList) { ClientsDtos.Add(new ClientDto2() { Id = client.Id, ClientId = client.ClientId ?? "0", ClientName = client.ClientName ?? "None", Description = client.Description ?? "None", UserCodeType = client.UserCodeType ?? "None", Admin = client.Id % 2 == 1 }); } } catch (Exception ex) { Console.WriteLine(ex); TempMessage = ex.Message; if (ex.InnerException != null) TempMessage += " : " + ex.InnerException.Message; } } public JsonResult OnPostRead([DataSourceRequest] DataSourceRequest request) { var res = new JsonResult(ClientsDtos.ToDataSourceResult(request)); return res; } public JsonResult OnPostUpdate([DataSourceRequest] DataSourceRequest request, ClientDto2 client) { // the updatedClientData contains the updated data (only one record at a time in this example) var updatedClientData = ClientsDtos.Where(x => x.Id == client.Id).Select(x => client); // test changing data here client.UserCodeType = "99"; TempMessage = $"Admin = {client.Admin}, Management = {client.Management}, Office = {client.Office} "; // use this data to update DB here and return the updated data return new JsonResult(new[] { client }.ToDataSourceResult(request, ModelState)); } } public class ClientDto2 { public int Id { get; set; } public string ClientId { get; set; } public string ClientName { get; set; } public string Description { get; set; } public string UserCodeType { get; set; } public bool Admin { get; set; } public bool Management { get; set; } public bool Office { get; set; } }}
@page@model Kendo.Examples.RazorPages.Pages.Manage.LabModel@using Kendo.Mvc.UI@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf@Html.AntiForgeryToken()@{ ViewData["Title"] = "Lab";}<h1>Lab</h1><form method="post"> @*FYI the following does not fire unless the page is reloaded it does not fire for a data update*@ @if (!string.IsNullOrEmpty(Model.TempMessage)) { var statusMessageClass = Model.TempMessage.StartsWith("Error") ? "danger" : "success"; @if (Model.TempMessage != "") { <div class="alert alert-@statusMessageClass alert-dismissible" role="alert"> <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button> @Model.TempMessage </div> } } @(Html.Kendo().Grid<ClientDto2>().Name("grid") .Columns(columns => { columns.Bound(column => column.ClientId).Width(100).Title("Client"); columns.Bound(column => column.ClientName); columns.Bound(column => column.Description); columns.Bound(column => column.UserCodeType); columns.Bound(column => column.Admin) .ClientTemplate( "<input class='k-checkbox' data-val=#: Admin# id='Admin#: id#' name='Admin' " + "type='checkbox' #= Admin ? checked='checked' : '' # onclick='return false;' value=#: Admin# >" + "<label for='Admin#: id#' class='k-checkbox-label'></label>"); columns.Bound(column => column.Management) .ClientTemplate( "<input class='k-checkbox' data-val=#: Management# id='Management#: id#' name='Management' " + "type='checkbox' #= Management ? checked='checked' : '' # onclick='return false;' value=#: Management# >" + "<label for='Management#: id#' class='k-checkbox-label'></label>"); columns.Bound(column => column.Office) .ClientTemplate( "<input class='k-checkbox' data-val=#: Office# id='Office#: id#' name='Office' " + "type='checkbox' #= Office ? checked='checked' : '' # onclick='return false;' value=#: Office# >" + "<label for='Office#: id#' class='k-checkbox-label'></label>"); columns.Command(column => { column.Edit(); }); }) .DataSource(ds => ds.Ajax() .Read(r => r.Url("/Manage/Lab?handler=Read").Data("forgeryToken")) .Update(u => u.Url("/Manage/Lab?handler=Update").Data("forgeryToken")) .Create(c => c.Url("/Manage/Lab?handler=Create").Data("forgeryToken")) .Destroy(d => d.Url("/Manage/Lab?handler=Destroy").Data("forgeryToken")) .Model(m => m.Id(id => id.Id)) .PageSize(20) ) .Scrollable() )</form><script type="text/javascript"> function forgeryToken() { return kendo.antiForgeryTokens(); }</script>
By far the biggest hurdle here was adding in the checkboxes. The default grid shows "true" and "false" until you go onto edit mode and then it shows an actual checkbox (BTW that comes from Shared/EditorTemplates/Boolean.cshtml). It sure would be nice if the grid default would be to show the checkboxes but since that is not the case I went in search of how to show them. At first I went down the rabbit hole at the https://demos.telerik.com/aspnet-core/grid/rowtemplate page - I could not get this to work. In my case it seems if you add ClientRowTemplate that wipes out any other column data and I could not get it to work like the display shows after many tries. Then I stumbled on the ClientTemplate (good luck finding any documentation on this one!) and after much trial and error I got a checkbox on the grid, but without a class and it was ugly and out of place so added the "k-checkbox" class and the checkbox disappeared. It turns out you need to add the label next to it or it disappears - WTF! Lastly I needed to make the checkbox read only since clicking it in browse mode would change it but that would not change the underlying data and so I found an HTML hack to add the onclick return false function which essentially makes it read only. - So holy crap this was a painful journey but I hope this post helps others.