diff --git a/src/Core/Components/DataGrid/FluentDataGrid.razor b/src/Core/Components/DataGrid/FluentDataGrid.razor index ebcd012f45..b30b54b566 100644 --- a/src/Core/Components/DataGrid/FluentDataGrid.razor +++ b/src/Core/Components/DataGrid/FluentDataGrid.razor @@ -52,7 +52,7 @@ { @if (Virtualize) { - if (_internalGridContext.TotalItemCount == 0) + if (_internalGridContext.TotalItemCount == 0 && _virtualizeComponent is not null) { @_renderEmptyContent } diff --git a/src/Core/Components/DataGrid/FluentDataGrid.razor.cs b/src/Core/Components/DataGrid/FluentDataGrid.razor.cs index fd4b4ce2c6..d0bb944d53 100644 --- a/src/Core/Components/DataGrid/FluentDataGrid.razor.cs +++ b/src/Core/Components/DataGrid/FluentDataGrid.razor.cs @@ -1302,19 +1302,34 @@ public async Task RefreshDataAsync(bool force = false) // Same as RefreshDataAsync, except without forcing a re-render. We use this from OnParametersSetAsync // because in that case there's going to be a re-render anyway. + [SuppressMessage("Design", "MA0051:Method is too long", Justification = "Not going to do artificial optimization because of some random arbitrary determined line count number")] private async Task RefreshDataCoreAsync() { // Move into a "loading" state, cancelling any earlier-but-still-pending load _pendingDataLoadCancellationTokenSource?.CancelAsync(); var thisLoadCts = _pendingDataLoadCancellationTokenSource = new CancellationTokenSource(); - if (_virtualizeComponent is not null) + if (Virtualize) { - // If we're using Virtualize, we have to go through its RefreshDataAsync API otherwise: - // (1) It won't know to update its own internal state if the provider output has changed - // (2) We won't know what slice of data to query for - await _virtualizeComponent.RefreshDataAsync(); + if (_virtualizeComponent is not null) + { + // If we're using Virtualize, we have to go through its RefreshDataAsync API otherwise: + // (1) It won't know to update its own internal state if the provider output has changed + // (2) We won't know what slice of data to query for + // ProvideVirtualizedItemsAsync updates _internalGridContext.Items and fires ItemsChanged, + // so no second query is needed here. + await _virtualizeComponent.RefreshDataAsync(); + _pendingDataLoadCancellationTokenSource = null; + return; + } + // If Virtualize is true but we don't have a reference to the component yet, + // it means we're still in the first render. The Virtualize component will call us when it's ready, + // so we can just wait for that instead of trying to load data now. _pendingDataLoadCancellationTokenSource = null; + thisLoadCts.Dispose(); + Loading = false; + StateHasChanged(); + return; } // If we're not using Virtualize, we build and execute a request against the items provider directly @@ -1365,6 +1380,7 @@ private async Task RefreshDataCoreAsync() // Gets called both by RefreshDataCoreAsync and directly by the Virtualize child component during scrolling [ExcludeFromCodeCoverage(Justification = "This method requires Virtualiztion which cannot be tested with bunit.")] + [SuppressMessage("Design", "MA0051:Method is too long", Justification = "Not going to do artificial optimization because of some random arbitrary determined line count number")] private async ValueTask> ProvideVirtualizedItemsAsync(ItemsProviderRequest request) { _lastRefreshedPaginationState = Pagination; @@ -1375,7 +1391,14 @@ private async Task RefreshDataCoreAsync() } else { - await Task.Delay(20); + try + { + await Task.Delay(20, request.CancellationToken); + } + catch (TaskCanceledException) + { + return default; + } } if (request.CancellationToken.IsCancellationRequested) @@ -1467,8 +1490,16 @@ private async ValueTask> ResolveItemsRequestA if (_asyncQueryExecutor is not null) { await OnItemsLoading.InvokeAsync(true); + + var resultArray = Array.Empty(); var totalItemCount = await _asyncQueryExecutor.CountAsync(Items, request.CancellationToken); - var resultArray = await _asyncQueryExecutor.ToArrayAsync(result, request.CancellationToken); + request.CancellationToken.ThrowIfCancellationRequested(); + + if (!request.Count.HasValue || request.Count.Value > 0) + { + resultArray = await _asyncQueryExecutor.ToArrayAsync(result, request.CancellationToken); + request.CancellationToken.ThrowIfCancellationRequested(); + } Loading = false; _asyncQueryExecuted = true; diff --git a/tests/Core/Components/DataGrid/FluentDataGridTests.razor b/tests/Core/Components/DataGrid/FluentDataGridTests.razor index f67665c707..282be748eb 100644 --- a/tests/Core/Components/DataGrid/FluentDataGridTests.razor +++ b/tests/Core/Components/DataGrid/FluentDataGridTests.razor @@ -367,7 +367,7 @@ var rows = cut.FindComponents>(); Assert.NotEmpty(rows); // Asserting that there are rows present - Assert.Equal(2, rows.Count); //In bUnit the actual height of the grid can't be determined, so we just check that at least one row is rendered. + Assert.True(rows.Count >= 1); //In bUnit the actual height of the grid can't be determined, so we just check that at least one row is rendered. } private async Task> RefreshItemsAsync(GridItemsProviderRequest req)