Skip to content

fix: [dev-5] DataGrid rendering performance is slow #4929

Description

@Bartsz

🐛 Bug Report

DataGrid takes a lot of time to apply changes after sorting or grouping (reordering columns also takes a lot of time).
For 200 rows and ~8 columns it takes ~500ms from click to show changes

💻 Repro or Code Sample

Steps to reproduce:

  1. Open weather page
  2. Sort by any column.
@page "/weather"
@using System.Diagnostics
@inject ILogger<Weather> Logger

<PageTitle>Weather</PageTitle>
 
<FluentDataGrid Id="weathergrid"
                Items="@forecasts"
                OnSortChanged="@HandleOnSortChanged" 
                GridTemplateColumns="1fr 1fr 1fr 2fr" TGridItem=WeatherForecast>
    <PropertyColumn Title="Date" Property="@(c => c!.Date)" Sortable="true" Align="DataGridCellAlignment.Start" />
    <PropertyColumn Title="Temp. (C)" Property="@(c => c!.TemperatureC)" Sortable="true" Align="DataGridCellAlignment.Center" />
    <PropertyColumn Title="Temp. (F)" Property="@(c => c!.TemperatureF)" Sortable="true" Align="DataGridCellAlignment.Center" />
    <PropertyColumn Title="Summary" Property="@(c => c!.Summary)" Sortable="true" Align="DataGridCellAlignment.End" />
</FluentDataGrid>

@code {
    private IQueryable<WeatherForecast>? forecasts;
    private Stopwatch _eventToRenderWatch = new();
    private int _renderCount;

    private void HandleOnSortChanged()
    {
        _eventToRenderWatch.Restart();
    }
    protected override void OnInitialized()
    {
        base.OnInitialized();

        forecasts = Enumerable.Range(1, 505).Select(index => new WeatherForecast
        {
            Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = (index % 5) switch
            {
                0 => "Freezing",
                1 => "Bracing",
                2 => "Chilly",
                3 => "Cool",
                4 => "Mild",
            }
        })
         .ToList()
         .AsQueryable();
    }

    protected override void OnAfterRender(bool firstRender)
    {
        _renderCount++;

        if (_eventToRenderWatch.IsRunning)
        {
            _eventToRenderWatch.Stop();
            Debug.WriteLine($"Event to render: {_eventToRenderWatch.Elapsed.TotalMilliseconds,7:N6}ms");
            _eventToRenderWatch.Reset();
        }
        Debug.WriteLine($"Render #{_renderCount}, firstRender={firstRender}"); 
    }

    public class WeatherForecast
    {
        public DateOnly Date { get; set; }
        public int TemperatureC { get; set; }
        public string? Summary { get; set; }
        public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
    }
}

🤔 Expected Behavior

At discussed scale, this should take less than few frames to render, less then 30ms would be good target to display changes - within 2 rendered frames on 60Hz refresh rate monitor.

😯 Current Behavior

Applying changes takes a lot of time and rendering/layout on the browser side is not an issue as seen on the screenshot below.
Screenshot from template project "weather" page with 505 rows and 4 columns => event takes 600ms in release mode
Layerize, Pre-paint and Layout takes total of ~65ms after the event.
Image

On this screenshot I think we can see that the wasm.function[213] takes 500ms and only 50ms is self time
Image

I've tried to see a CPU Usage profile from .NET but it doesn't show any detailed split.

💁 Possible Solution

🔦 Context

N/A

🌍 Your Environment

  • Windows, Laptop PC
  • Google Chrome
  • .NET10, Blazor, Fluent UI v5 RC3

Metadata

Metadata

Assignees

No one assigned

    Labels

    improvementA non-feature-adding improvementv5For the next major version

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions