DataGrid self-refefrencing hierarchy not working

Hello,

I am seeing an issue with the DataGrid when trying to use self referencing hierarchi and it's something to do with the class that is the type of the Datagrid.

@using EsioBudget.Application.Budget.DataTransferObjects
@using MediatR
@using Microsoft.Extensions.Localization
@if (_model == null)
{
    <CircularProgressBar></CircularProgressBar>
}
else
{
    <RadzenDataGrid @ref="_grid" AllowFiltering="true" AllowSorting="true" AllowColumnResize="true"
                    Data="@_model.Items" RowRender="@RowRender" LoadChildData="@LoadChildData" TItem="Dummy"
                    RowCollapse="@(args => _grid.ColumnsCollection.ToList().ForEach(c => c.ClearFilters()))">
        <Columns>
            <RadzenDataGridColumn Title="Employee">
                <Template Context="data">
                    @data.Name
                </Template>
            </RadzenDataGridColumn>
        </Columns>
    </RadzenDataGrid>
}

@code {

    [Parameter] public IEnumerable<MetricLineData> MetricLines { get; set; }
    [Parameter] public IEnumerable<IntervalData> Intervals { get; set; }
    [Parameter] public bool ShowHeaders { get; set; }

    [Inject] public required IMediator Mediator { get; set; }
    [Inject] public required NotificationService NotificationService { get; set; }
    [Inject] public required IStringLocalizer<AppResources> Localizer { get; set; }

    private class Dummy(string name, IEnumerable<Dummy> subItems)
    {
        public string Name { get; set; } = name;
        public IEnumerable<Dummy> SubItems { get; set; } = subItems;
    }

    private class ViewModel(IEnumerable<Dummy> items, IEnumerable<MetricLineData> lines, IEnumerable<IntervalData> intervals)
    {
        public IEnumerable<Dummy> Items = items;
        public IEnumerable<MetricLineData> MetricLines { get; set; } = lines;
        public IEnumerable<IntervalData> Intervals { get; set; } = intervals;
    }

    private ViewModel _model;

    private RadzenDataGrid<Dummy> _grid;

    protected override async Task OnParametersSetAsync()
    {
        _model = new ViewModel(
            [new Dummy("Item 1", [new Dummy("SubItem1", [])])],
            MetricLines,
            Intervals
        );
    }

    void RowRender(RowRenderEventArgs<Dummy> args)
    {
        args.Expandable = args.Data.SubItems.Any();
    }

    void LoadChildData(DataGridLoadChildDataEventArgs<Dummy> args)
    {
        args.Data = args.Item.SubItems;
    }
}

In this component example, the expanding of the item row works fine when using the "Dummy" class. When I change however the type to use the "MetricLineData" which I made, then the expanding button does not work anymore.

This is the class in question:

public class MetricLineData(string name, List<MetricData> metrics, List<MetricLineData>? submetrics, decimal total)
{
    public string Name { get; set; } = name;
    public List<MetricData>  Metrics { get; set; } = metrics;
    
    public List<MetricLineData>? MetricLines { get; set; } = submetrics;
    public decimal Total { get; set; } = total;

    public static MetricLineData Map(MetricLine metricLine)
    {
        return new MetricLineData(
            metricLine.Name,
            metricLine.Metrics.Select(x => MetricData.Map(x)).ToList(),
            metricLine.MetricLines?.Select(x => Map(x)).ToList(),
            metricLine.Total
            );
    }

    public MetricData? GetForInterval(IntervalData interval)
    {
        return Metrics.FirstOrDefault(x => x.Interval.Index == interval.Index);
    }
}

I'd like to know what I'm doing wrong with this class that prevents the hierarcy expantion

@using EsioBudget.Application.Budget.DataTransferObjects
@using MediatR
@using Microsoft.Extensions.Localization
@if (_model == null)
{
    <CircularProgressBar></CircularProgressBar>
}
else
{
    <RadzenDataGrid @ref="_grid" AllowFiltering="true" AllowSorting="true" AllowColumnResize="true"
                    Data="@_model.MetricLines" RowRender="@RowRender" LoadChildData="@LoadChildData" TItem="MetricLineData"
                    RowCollapse="@(args => _grid.ColumnsCollection.ToList().ForEach(c => c.ClearFilters()))">
        <Columns>
            <RadzenDataGridColumn Title="Employee">
                <Template Context="data">
                    @data.Name
                </Template>
            </RadzenDataGridColumn>
        </Columns>
    </RadzenDataGrid>
}

@code {

    [Parameter] public IEnumerable<MetricLineData> MetricLines { get; set; }
    [Parameter] public IEnumerable<IntervalData> Intervals { get; set; }
    [Parameter] public bool ShowHeaders { get; set; }

    [Inject] public required IMediator Mediator { get; set; }
    [Inject] public required NotificationService NotificationService { get; set; }
    [Inject] public required IStringLocalizer<AppResources> Localizer { get; set; }

    private class Dummy(string name, IEnumerable<Dummy> subItems)
    {
        public string Name { get; set; } = name;
        public IEnumerable<Dummy> SubItems { get; set; } = subItems;
    }

    private class ViewModel(IEnumerable<Dummy> items, IEnumerable<MetricLineData> lines, IEnumerable<IntervalData> intervals)
    {
        public IEnumerable<Dummy> Items = items;
        public IEnumerable<MetricLineData> MetricLines { get; set; } = lines;
        public IEnumerable<IntervalData> Intervals { get; set; } = intervals;
    }

    private ViewModel _model;

    private RadzenDataGrid<MetricLineData> _grid;

    protected override async Task OnParametersSetAsync()
    {
        _model = new ViewModel(
            [new Dummy("Item 1", [new Dummy("SubItem1", [])])],
            MetricLines,
            Intervals
        );
    }

    void RowRender(RowRenderEventArgs<MetricLineData> args)
    {
        args.Expandable = args.Data.MetricLines.Any();
    }

    void LoadChildData(DataGridLoadChildDataEventArgs<MetricLineData> args)
    {
        args.Data = args.Item.MetricLines;
    }
}

This is the class when I use my own class added in for the hierarchy

Any idea on what is causing this issue?

I'm afraid that without debugging I can hardly tell what's causing the issue.

Is there any way I can help? When I debugged and looked at the RowRender and LoadChildData, I could see that when clicking on the item handle, the child items were present there in the variable, and when clicking on the LoadChildData the subitems were properly loaded from the sub items into the subitem list

Please supply runnable code that can be tested in our demos.

It's unfortunatelly not possible to do that ... if it were then I would know what the issue was to fix it ...

I am debugging as deep as i can and I can see in the OnAfterRenderAsync method that when I click an item in the table, the expandedItems list in the grid is populated with the intended item:

So the state of the grid says that it should be expanded with the item, however the grid stays unexpanded with no UI changes. This makes me think that something related to the [Parameter] type data messes up the my component rerendering. Since this is not an issue in the example code where the data is not injected but retrieved from the mock dbContext

I have found the issue to be that when the assigned data variable to the grid was a generic IEnumerable type, then the grid could not function, even though in your example the data parameter is declared as IEnumerable.

This was in my case happening. If however I call the AsList() on the enumerator then it works as expected. Not sure why the grid behaves this ways with IEnumerator but not with List objects