Loading DataGridSettings with null Width Freezes page

If a DataGrid column has a width set and a DataGridSettings is loaded w/ a null width for that column, the page freezes.

On DataGrid Save settings filter/sort some columns so a DataGridSettings gets set to localstorage. Then edit source and use the code below, then click "Load saved settings", the page just freezes. If you set a break point in RadzenDataGrid's OnAfterRenderAsync and LoadSettingsInternal they keep getting called over and over.

  • added a width to the Title column
  • commented out the OnAfterRender method
  • made a button to manually trigger the load
  • made LoadStateAsync set all widths to null before using it in the DataGrid
@using Radzen
@using RadzenBlazorDemos.Data
@using RadzenBlazorDemos.Models.Northwind
@using Microsoft.EntityFrameworkCore
@using RadzenBlazorDemos.Services
@using Microsoft.JSInterop
@using System.Text.Json

@inject IJSRuntime JSRuntime
@inject NavigationManager NavigationManager

@inherits DbContextPage

<p>This example shows how to save/load DataGrid state using Settings property.</p>
<p>The state includes current page index, page size, groups and columns filter, sort, order, width and visibility.</p>
<RadzenButton Click="@(args => LoadStateAsync())" Text="Load saved settings" Style="margin-bottom: 16px" />
<RadzenButton Click="@(args => Settings = null)" Text="Clear saved settings" Style="margin-bottom: 16px" />
<RadzenButton Click="@(args => NavigationManager.NavigateTo("/datagrid-save-settings", true))" Text="Reload" Style="margin-bottom: 16px" />
<RadzenDataGrid @bind-Settings="@Settings" AllowFiltering="true" AllowColumnPicking="true" AllowGrouping="true" AllowPaging="true" PageSize="4"
                AllowSorting="true" AllowMultiColumnSorting="true" ShowMultiColumnSortingIndex="true" 
                AllowColumnResize="true" AllowColumnReorder="true" ColumnWidth="200px"
                FilterPopupRenderMode="PopupRenderMode.OnDemand" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" Data="@employees">
    <Columns>
        <RadzenDataGridColumn Title="Employee" Sortable="false" Filterable="false" UniqueID="Employee">
            <Template Context="data">
                <RadzenImage Path="@data.Photo" Style="width: 40px; height: 40px;" class="rz-border-radius-2 rz-me-2" AlternateText="@(data.FirstName + " " + data.LastName)" />
                @data.FirstName @data.LastName
            </Template>
        </RadzenDataGridColumn>
        <RadzenDataGridColumn Property="@nameof(Employee.Title)" Title="Title" Width="150px"/>
        <RadzenDataGridColumn Property="@nameof(Employee.EmployeeID)" Title="Employee ID" />
        <RadzenDataGridColumn Property="@nameof(Employee.HireDate)" Title="Hire Date" FormatString="{0:d}" />
        <RadzenDataGridColumn Property="@nameof(Employee.City)" Title="City" />
        <RadzenDataGridColumn Property="@nameof(Employee.Country)" Title="Country" />
    </Columns>
</RadzenDataGrid>

<EventConsole @ref=@console />

@code {
    IEnumerable<Employee> employees;
    EventConsole console;

    protected override async Task OnInitializedAsync()
    {
        await base.OnInitializedAsync();

        employees = dbContext.Employees;
    }

    DataGridSettings _settings;
    public DataGridSettings Settings 
    { 
        get
        {
            return _settings;
        }
        set
        {
            if (_settings != value)
            {
                _settings = value;
                InvokeAsync(SaveStateAsync);
            }
        }
    }

    private async Task LoadStateAsync()
    {
        await Task.CompletedTask;

        var result = await JSRuntime.InvokeAsync<string>("window.localStorage.getItem", "Settings");
        if (!string.IsNullOrEmpty(result))
        {
            Console.WriteLine($"Before: {result}");
            var dgs = JsonSerializer.Deserialize<DataGridSettings>(result); 

            //Simulate loading data that didnt store width
            foreach(var col in dgs.Columns)
            {
                Console.WriteLine($"{col.Property} -- {col.Width}");
                col.Width = null;
            }
            
            Console.WriteLine($"After: {JsonSerializer.Serialize<DataGridSettings>(dgs)}");

            _settings = dgs;
        }
    }

    private async Task SaveStateAsync()
    {
        await Task.CompletedTask;

        await JSRuntime.InvokeVoidAsync("window.localStorage.setItem", "Settings", JsonSerializer.Serialize<DataGridSettings>(Settings));
    }

    // protected override async Task OnAfterRenderAsync(bool firstRender)
    // {
    //     if (firstRender)
    //     {
    //         await LoadStateAsync();
    //         StateHasChanged();
    //     }
    // }
}

Honestly not sure what's causing this cycle - by default Width is null and our demo works normally when loading columns with or without Width set:


It's happening in my app after removing a DataGrid's LoadData which I don't need after switching a column to use CustomFilter. The DataGridSetting is loaded from the database that has width = null for a column.

settingChanged needs to be set to false in DataGrid's OnAfterRenderAsync

if (settings != null && settingsChanged)
{
     await LoadSettingsInternal(settings);
     settingsChanged = false;
}

DataGrid's OnAfterRenderAsync is being called over and over because in LoadSettingsInternal, gridColumn.GetWidth() is returning the Width="100px" attribute's value, and so it sees it as always needing to be updated:

if (gridColumn.GetWidth() != column.Width)
{
    gridColumn.SetWidth(column.Width);
    shouldUpdateState = true;
}

shouldUpdateState later calls Reload => ReloadInternal which Calls StateHasChanged when LoadData isn't set. Which I'm assuming triggers another OnAfterRenderAsync after ReloadInternal finishes.

It's caused by adding Width to a column in html, and then loading a previous saved setting that didn't have width set.

Goto the Save/Load Settings page... click the title column so it's sorted and saved. Then edit the page and add Width="200px" to the title's RadzenDataGridColumn. Then hit run, it freezes for the reasons mentioned above

This will help:

It will be part of our next update later the week.

1 Like