I've found a bit of inconsistent behaviour in the InCell mode that I think is a bug?:
- If you click into a column bound to a boolean field, then click on another non-editable cell in the grid, this will not end the edit mode for the boolean column (so, it still shows a checkbox).
- Whereas, for a string or date column, if you click into the field and put it into edit mode, then click onto a non-editable area of the grid that will end the edit mode.
I think the second of those behaviours is correct and what a user would expect.
I've attached a gif showing what I mean. I'm on version 2.20.
This is the code for the example in the gif.
@page "/InCell"@using Telerik.Blazor@using Telerik.Blazor.ComponentsClick a cell, edit it and click outside of the cell to see the change.<br /><strong>Editing is prevented for the first two items.</strong><TelerikGrid Data=@MyData EditMode="@GridEditMode.Incell" Pageable="true" Height="500px" Sortable="true" OnUpdate="@UpdateHandler" OnEdit="@EditHandler" OnDelete="@DeleteHandler" OnCreate="@CreateHandler"> <GridToolBar> <GridCommandButton Command="Add" Icon="add">Add Employee</GridCommandButton> </GridToolBar> <GridColumns> <GridColumn Field=@nameof(SampleData.ID) Title="ID" Editable="false" /> <GridColumn Field=@nameof(SampleData.Name) Title="Name" /> <GridColumn Field=@nameof(SampleData.Happy) /> <GridCommandColumn> <GridCommandButton Command="Save" Icon="save" ShowInEdit="true">Update</GridCommandButton> <GridCommandButton Command="Delete" Icon="delete">Delete</GridCommandButton> </GridCommandColumn> </GridColumns></TelerikGrid>@code { void EditHandler(GridCommandEventArgs args) { SampleData item = (SampleData)args.Item; // prevent opening for edit based on condition if (item.ID < 3) { args.IsCancelled = true;// the general approach for cancelling an event } Console.WriteLine("Edit event is fired for column " + args.Field); } async Task UpdateHandler(GridCommandEventArgs args) { SampleData item = (SampleData)args.Item; // perform actual data source operations here through your service await MyService.Update(item); // update the local view-model data with the service data await GetGridData(); Console.WriteLine("Update event is fired."); } async Task DeleteHandler(GridCommandEventArgs args) { SampleData item = (SampleData)args.Item; // perform actual data source operation here through your service await MyService.Delete(item); // update the local view-model data with the service data await GetGridData(); Console.WriteLine("Delete event is fired."); } async Task CreateHandler(GridCommandEventArgs args) { SampleData item = (SampleData)args.Item; // perform actual data source operation here through your service await MyService.Create(item); // update the local view-model data with the service data await GetGridData(); Console.WriteLine("Create event is fired."); } // in a real case, keep the models in dedicated locations, this is just an easy to copy and see example public class SampleData { public int ID { get; set; } public string Name { get; set; } public bool Happy { get; set; } } public List<SampleData> MyData { get; set; } async Task GetGridData() { MyData = await MyService.Read(); } protected override async Task OnInitializedAsync() { await GetGridData(); } // the following static class mimics an actual data service that handles the actual data source // replace it with your actual service through the DI, this only mimics how the API can look like and works for this standalone page public static class MyService { private static List<SampleData> _data { get; set; } = new List<SampleData>(); public static async Task Create(SampleData itemToInsert) { itemToInsert.ID = _data.Count + 1; _data.Insert(0, itemToInsert); } public static async Task<List<SampleData>> Read() { var happy = false; if (_data.Count < 1) { for (int i = 1; i < 50; i++) { happy = !happy; _data.Add(new SampleData() { ID = i, Name = "Name " + i.ToString(), Happy = happy }); } } return await Task.FromResult(_data); } public static async Task Update(SampleData itemToUpdate) { var index = _data.FindIndex(i => i.ID == itemToUpdate.ID); if (index != -1) { _data[index] = itemToUpdate; } } public static async Task Delete(SampleData itemToDelete) { _data.Remove(itemToDelete); } }}