Skip to content

Commit 13fac20

Browse files
authored
Fixed async 'Loading' state flag feedback and Virtual mode switch render handling (#4343)
1 parent 6180d3a commit 13fac20

File tree

1 file changed

+30
-16
lines changed

1 file changed

+30
-16
lines changed

src/Core/Components/DataGrid/FluentDataGrid.razor.cs

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ public partial class FluentDataGrid<TGridItem> : FluentComponentBase, IHandleEve
376376
// async query APIs that might be available. We have built-in support for using EF Core's async query APIs.
377377
private IAsyncQueryExecutor? _asyncQueryExecutor;
378378
private AsyncServiceScope? _scope;
379+
private bool _asyncQueryExecuted;
379380

380381
// We cascade the InternalGridContext to descendants, which in turn call it to add themselves to _columns
381382
// This happens on every render so that the column list can be updated dynamically
@@ -411,6 +412,7 @@ public partial class FluentDataGrid<TGridItem> : FluentComponentBase, IHandleEve
411412
// things have changed, and to discard earlier load attempts that were superseded.
412413
private PaginationState? _lastRefreshedPaginationState;
413414
private IQueryable<TGridItem>? _lastAssignedItems;
415+
private bool? _lastVirtualizationMode;
414416

415417
private GridItemsProvider<TGridItem>? _lastAssignedItemsProvider;
416418
private CancellationTokenSource? _pendingDataLoadCancellationTokenSource;
@@ -483,12 +485,23 @@ protected override Task OnParametersSetAsync()
483485
_lastAssignedItemsProvider = ItemsProvider;
484486
_lastAssignedItems = Items;
485487
_asyncQueryExecutor = AsyncQueryExecutorSupplier.GetAsyncQueryExecutor(_scope.Value.ServiceProvider, Items);
488+
_asyncQueryExecuted = false;
486489
}
487490

488491
var paginationStateHasChanged =
489492
Pagination?.ItemsPerPage != _lastRefreshedPaginationState?.ItemsPerPage
490493
|| Pagination?.CurrentPageIndex != _lastRefreshedPaginationState?.CurrentPageIndex;
491494

495+
if (_lastVirtualizationMode != Virtualize)
496+
{
497+
_lastVirtualizationMode = Virtualize;
498+
_asyncQueryExecuted = false;
499+
}
500+
if (Loading == true && _asyncQueryExecutor is not null && _asyncQueryExecuted)
501+
{
502+
Loading = false; // switch to uncontrolled loading state after first IAsyncQueryExecutor completes
503+
}
504+
492505
var mustRefreshData = dataSourceHasChanged || paginationStateHasChanged || EffectiveLoadingValue;
493506

494507
// We don't want to trigger the first data load until we've collected the initial set of columns,
@@ -865,7 +878,7 @@ private async Task RefreshDataCoreAsync()
865878
{
866879
Pagination?.SetTotalItemCountAsync(_internalGridContext.TotalItemCount);
867880
}
868-
if ((_internalGridContext.TotalItemCount > 0 && Loading is null) || _lastError != null)
881+
if ((_internalGridContext.TotalItemCount > 0 && Loading != false) || _lastError != null)
869882
{
870883
Loading = false;
871884
StateHasChanged();
@@ -904,13 +917,7 @@ private async ValueTask<GridItemsProviderResult<TGridItem>> ResolveItemsRequestA
904917
}
905918
else if (Items is not null)
906919
{
907-
if (_asyncQueryExecutor is not null)
908-
{
909-
await OnItemsLoading.InvokeAsync(true);
910-
}
911-
var totalItemCount = _asyncQueryExecutor is null ? Items.Count() : await _asyncQueryExecutor.CountAsync(Items, request.CancellationToken);
912-
_internalGridContext.TotalItemCount = totalItemCount;
913-
IQueryable<TGridItem>? result;
920+
var result = Items;
914921
if (RefreshItems is null)
915922
{
916923
result = request.ApplySorting(Items).Skip(request.StartIndex);
@@ -919,12 +926,24 @@ private async ValueTask<GridItemsProviderResult<TGridItem>> ResolveItemsRequestA
919926
result = result.Take(request.Count.Value);
920927
}
921928
}
929+
if (_asyncQueryExecutor is not null)
930+
{
931+
await OnItemsLoading.InvokeAsync(true);
932+
var totalItemCount = await _asyncQueryExecutor.CountAsync(Items, request.CancellationToken);
933+
var resultArray = await _asyncQueryExecutor.ToArrayAsync(result, request.CancellationToken);
934+
935+
Loading = false;
936+
_asyncQueryExecuted = true;
937+
_internalGridContext.TotalItemCount = totalItemCount;
938+
939+
return GridItemsProviderResult.From(resultArray, totalItemCount);
940+
}
922941
else
923942
{
924-
result = Items;
943+
var totalItemCount = Items.Count();
944+
_internalGridContext.TotalItemCount = totalItemCount;
945+
return GridItemsProviderResult.From([.. result], totalItemCount);
925946
}
926-
var resultArray = _asyncQueryExecutor is null ? [.. result] : await _asyncQueryExecutor.ToArrayAsync(result, request.CancellationToken);
927-
return GridItemsProviderResult.From(resultArray, totalItemCount);
928947
}
929948
}
930949
catch (OperationCanceledException oce) when (oce.CancellationToken == request.CancellationToken)
@@ -939,11 +958,6 @@ private async ValueTask<GridItemsProviderResult<TGridItem>> ResolveItemsRequestA
939958
{
940959
if (Items is not null && _asyncQueryExecutor is not null)
941960
{
942-
if (Loading == true)
943-
{
944-
Loading = false;
945-
StateHasChanged();
946-
}
947961
await OnItemsLoading.InvokeAsync(false);
948962
}
949963
}

0 commit comments

Comments
 (0)