You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MudBlazor DataGrid服务端分页切换后选中行无法高亮(RowClassFunc失效)

问题描述

使用带服务端分页和过滤功能的MudBlazor DataGrid时,选中行后数据保存正常,但切换页面时无法让之前选中的行重新显示选中状态。尝试通过RowClassFunc为选中行添加"selected"类,但该方案未生效。

相关代码如下:

<MudDataGrid 
            T="ObservationListModel" 
            MultiSelection="@true" 
            @ref="_dataGrid" 
            @bind-SelectedItems="selectedItems" 
            ServerData="LoadGridData" 
            SortMode="SortMode.Multiple" 
            Filterable="true"
            RowClassFunc="SelectedRowClassFunc"
            Hideable="false" 
            Elevation="5" 
            Dense="@true">
            <ToolBarContent>
                <MudSpacer />
                <MudTextField T="string" Value="@_requestDto.Search" Placeholder="Search" Adornment="Adornment.Start" Immediate="false"
                              AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" Class="mt-0" ValueChanged="OnSearchChange"></MudTextField>
            </ToolBarContent>
            <Columns>
                <SelectColumn T="ObservationListModel" />
                <TemplateColumn Sortable="@false" Filterable="@false" Title="Detail" >
                    <CellTemplate>
                        <MudStack Row>
                            <MudButton Size="@Size.Small" Variant="@Variant.Filled" Href="@($"obsdetail/{context.Item.ReferenceID}/{context.Item.OriginalDataID}")" Color="@Color.Primary">View</MudButton>
                        </MudStack>
                    </CellTemplate>
                </TemplateColumn>
                <PropertyColumn Property="x => x.ScientificName" Title="Scientific Name" Sortable="true" />
                <PropertyColumn Property="x => x.ObservationDate" Title="Observation Date" Sortable="true" Filterable="false" />
                <PropertyColumn Property="x => x.Class" Title="Class" Sortable="true"/>
                <PropertyColumn Property="x => x.CountyName" Title="County" Sortable="true" />
                <PropertyColumn Property="x => x.Observer" Title="Observer" Sortable="true" />
                <PropertyColumn Property="x => x.ReviewStatus" Title="Review Status" Sortable="true" />
            </Columns>
            <PagerContent>
                <MudText>@($"{selectedItems.Count} items selected")</MudText>
                <MudDataGridPager T="ObservationListModel"/>
            </PagerContent>
        </MudDataGrid>
@code {

    private MudDataGrid<ObservationListModel>? _dataGrid;
    private ObsRequestModel _requestDto = new();
    private HashSet<ObservationListModel> selectedItems { get; set; } = new HashSet<ObservationListModel>();

    private async Task Search()
    {
        if (_dataGrid is not null)
        {
            await _dataGrid!.ReloadServerData();
        }
    }

    private async Task OnSearchChange(string newValue)
    {
        _requestDto.Search = newValue;
        await Search();
    }

    private async Task<GridData<ObservationListModel>> LoadGridData(GridState<ObservationListModel> state)
    {
        _requestDto.Filters.Clear();
        _requestDto.Page = state.Page + 1;
        _requestDto.PageSize = state.PageSize;

        // Extract sorting information
        var sorting = state.SortDefinitions.FirstOrDefault(); // Assuming single column sorting
        if (sorting != null)
        {
            _requestDto.SortColumn = sorting.SortBy;
            _requestDto.SortDirection = sorting.Descending == false ? "asc" : "desc"; // Convert Enum to string or appropriate format
        }

        // Extract filtering information
        foreach (var filter in state.FilterDefinitions)
        {
            if (filter.Value != null) {

                var colString = filter.Title.ToString();
                var valString = colString == "County" ? await ReferenceService.GetCountyFips(filter.Value.ToString()) : filter.Value.ToString();

                _requestDto.Filters.Add(new FilterDefinition
                {
                    Column = colString,
                    Operator = filter.Operator.ToString(),
                    Value = valString
                });
            } 
            else if (filter.Operator.ToLower() == "is empty" || filter.Operator.ToLower() == "is not empty")
            {
                _requestDto.Filters.Add(new FilterDefinition
                {
                    Column = filter.Title.ToString(),
                    Operator = filter.Operator.ToString(),
                    Value = "0", // Assuming the value is a string, adjust as necessary
                });
            } 

        }

        ObListDTO Response = await ReferenceService.GetAllObs(_requestDto);
        GridData<ObservationListModel> data = new()
        {
            Items = Response.Items,
            TotalItems = Response.ItemTotalCount
        };

        return data;
    }

    private async Task OnStartDateChanged(DateTime? newDate)
    {
        _requestDto.StartDate = newDate;
        await DateChange();
    }

    private async Task OnEndDateChanged(DateTime? newDate)
    {
        _requestDto.EndDate = newDate;
        await DateChange();
    }

    private async Task DateChange()
    {
        if (_dataGrid is not null)
        {
            await _dataGrid!.ReloadServerData();
        }
    }

    public void Dispose()
    {
        
    }

    private string SelectedRowClassFunc(ObservationListModel element, int rowNumber)
    {
        return selectedItems.Contains(element) ? "selected" : string.Empty;
    }
}
解决方案

问题核心:HashSet<ObservationListModel>默认用对象引用判断相等性,服务端分页返回的是新创建的ObservationListModel实例,即使数据内容和之前选中的行一致,引用不同导致selectedItems.Contains(element)返回false,选中样式不生效。

方案1:重写模型的相等性判断

在ObservationListModel类中重写Equals和GetHashCode方法,基于唯一标识(比如ReferenceID和OriginalDataID)判断对象相等:

public class ObservationListModel
{
    // 你的现有属性
    public int ReferenceID { get; set; }
    public int OriginalDataID { get; set; }
    // ...其他属性

    public override bool Equals(object obj)
    {
        if (obj is not ObservationListModel other)
            return false;
        return ReferenceID == other.ReferenceID && OriginalDataID == other.OriginalDataID;
    }

    public override int GetHashCode()
    {
        return HashCode.Combine(ReferenceID, OriginalDataID);
    }
}

修改后HashSet能正确识别内容相同的不同实例,RowClassFunc的判断会自动生效。

方案2:用唯一ID集合跟踪选中项

如果不想修改模型类,可改用存储选中项的唯一标识,而非整个对象:

步骤1:修改选中项存储

// 替换原有的HashSet<ObservationListModel>
private HashSet<Tuple<int, int>> selectedItemIds { get; set; } = new();
// 保留用于DataGrid绑定的临时集合
private HashSet<ObservationListModel> selectedItems { get; set; } = new();

步骤2:同步选中项到ID集合

给MudDataGrid添加SelectedItemsChanged事件:

<MudDataGrid 
    ...
    @bind-SelectedItems="selectedItems"
    SelectedItemsChanged="OnSelectedItemsChanged"
    ...>

实现事件处理逻辑:

private void OnSelectedItemsChanged(HashSet<ObservationListModel> items)
{
    selectedItemIds.Clear();
    foreach (var item in items)
    {
        selectedItemIds.Add(Tuple.Create(item.ReferenceID, item.OriginalDataID));
    }
}

步骤3:修改RowClassFunc判断逻辑

private string SelectedRowClassFunc(ObservationListModel element, int rowNumber)
{
    return selectedItemIds.Contains(Tuple.Create(element.ReferenceID, element.OriginalDataID)) ? "selected" : string.Empty;
}

步骤4:切换页面后恢复选中状态

在LoadGridData方法返回数据后,手动匹配当前页的选中项:

private async Task<GridData<ObservationListModel>> LoadGridData(GridState<ObservationListModel> state)
{
    // ...原有逻辑

    ObListDTO Response = await ReferenceService.GetAllObs(_requestDto);
    GridData<ObservationListModel> data = new()
    {
        Items = Response.Items,
        TotalItems = Response.ItemTotalCount
    };

    // 恢复当前页的选中状态
    selectedItems.Clear();
    foreach (var item in data.Items)
    {
        if (selectedItemIds.Contains(Tuple.Create(item.ReferenceID, item.OriginalDataID)))
        {
            selectedItems.Add(item);
        }
    }

    return data;
}

内容的提问来源于stack exchange,提问作者Travis.fahey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 16:24:59