Unplanned
Last Updated: 07 Jul 2026 07:17 by Sadik
Sadik
Created on: 07 Jul 2026 07:17
Category: Grid
Type: Bug Report
1
Grid remains in in-cell edit mode when clicking outside an open DatePicker editor

Customers report inconsistent in-cell editing behavior with DatePicker columns in the Grid.

  • Case 1: click a date cell to enter edit mode, then click outside the Grid — edit mode terminates.
  • Case 2: click a date cell to enter edit mode, open the DatePicker popup, then click outside the Grid — the popup closes but the cell remains stuck in edit mode until pressing Esc or clicking another cell.

Here is a REPL test page that reproduces the issue (first date column) and provides a workaround (second date column):

https://blazorrepl.telerik.com/QAErkrEh090ykIxR16

The workaround relies on Grid EditorTemplate, the DatePicker OnClose event, and programmatic Grid edit mode management. The relevant code is:

@using System.ComponentModel.DataAnnotations

<TelerikGrid @ref="@GridRef"
             Data="@GridData"
             EditMode="@GridEditMode.Incell"
             OnUpdate="@OnGridUpdate"
             OnCreate="@OnGridCreate">
    <GridToolBarTemplate>
        <GridCommandButton Command="Add">Add Item</GridCommandButton>
    </GridToolBarTemplate>
    <GridColumns>
        <GridColumn Field="@nameof(Product.Name)" />
        <GridColumn Field="@nameof(Product.StartDate)" Title="BUG" DisplayFormat="{0:d}" />
        <GridColumn Field="@nameof(Product.EndDate)" Title="WORKAROUND" DisplayFormat="{0:d}">
            <EditorTemplate>
                @{ var editItem = (Product)context; }
                <TelerikDatePicker Value="editItem.EndDate"
                                   ValueChanged="@((DateTime? newValue) => OnGridDatePickerValueChanged(newValue, editItem))"
                                   ValueExpression="@( () => editItem.EndDate )"
                                   OnClose="@(async () => await OnGridDatePickerClose(editItem))" />
            </EditorTemplate>
        </GridColumn>
    </GridColumns>
</TelerikGrid>

@code {
    #nullable enable

    private TelerikGrid<Product>? GridRef;
    private List<Product> GridData { get; set; } = new();

    private int LastId { get; set; }

    private DateTime LastDatePickerValueChanged { get; set; } = DateTime.Now;

    private void OnGridDatePickerValueChanged(DateTime? newValue, Product editItem)
    {
        editItem.EndDate = newValue;
        LastDatePickerValueChanged = DateTime.Now;
    }

    private async Task OnGridDatePickerClose(Product editItem)
    {
        if (DateTime.Now - LastDatePickerValueChanged > TimeSpan.FromMilliseconds(500))
        {
            GridState<Product> gridState = GridRef!.GetState();

            if (gridState.EditItem is not null && gridState.EditItem.Id == editItem.Id)
            {
                // Uncomment to perform an item update instead of cancel
                // OnGridUpdate(new GridCommandEventArgs { Item = editItem });

                gridState.OriginalEditItem = null!;
                gridState.EditItem = null!;

                await GridRef.SetStateAsync(gridState);
            }
        }
    }

    private void OnGridCreate(GridCommandEventArgs args)
    {
        var createdItem = (Product)args.Item;

        createdItem.Id = ++LastId;

        GridData.Insert(0, createdItem);
    }

    private void OnGridUpdate(GridCommandEventArgs args)
    {
        var updatedItem = (Product)args.Item;
        var originalItemIndex = GridData.FindIndex(i => i.Id == updatedItem.Id);

        if (originalItemIndex != -1)
        {
            GridData[originalItemIndex] = updatedItem;
        }
    }

    protected override void OnInitialized()
    {
        for (int i = 1; i <= 5; i++)
        {
            GridData.Add(new Product()
            {
                Id = ++LastId,
                Name = $"Product {LastId}",
                Price = Random.Shared.Next(0, 100) * 1.23m,
                Quantity = Random.Shared.Next(0, 1000),
                StartDate = DateTime.Today.AddDays(-Random.Shared.Next(60, 1000)),
                EndDate = DateTime.Today.AddDays(Random.Shared.Next(1, 60)),
                IsActive = LastId % 4 > 0
            });
        }
    }

    public class Product
    {
        public int Id { get; set; }
        [Required]
        public string Name { get; set; } = string.Empty;
        public decimal Price { get; set; }
        public int Quantity { get; set; }
        public DateTime? StartDate { get; set; }
        public DateTime? EndDate { get; set; }
        public bool IsActive { get; set; }
    }
}

0 comments