-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Description
Is there an existing issue for this?
- I have searched the existing issues
Describe the bug
Hi,
Problem:
On QuickGrid when using "ItemsProvider" and "Virtualize" then ItemsProvider callback is called twice on the initial load and the first time it is called with GridItemsProviderRequest.Count=null.
Also see the example "Filtering remote data" here:
https://aspnet.github.io/quickgridsamples/filtering/
When loading there are two requests and in the first request Count is null:
https://api.fda.gov/food/enforcement.json?skip=0
https://api.fda.gov/food/enforcement.json?skip=0&limit=14
Issue:
In QuickGrid.razor the <ColumnsCollectedNotifier TGridItem="TGridItem" />
(line 12) is called before <Virtualize @ref="@_virtualizeComponent"
(line 22).
The first call to the ItemsProvider callback (with Count=null) is because of the call to RefreshDataCoreAsync
in the columnsFirstCollectedSubscriber
setup in the constructor of QuickGrid:
public QuickGrid()
{
_columns = new();
_internalGridContext = new(this);
_currentPageItemsChanged = new(EventCallback.Factory.Create<PaginationState>(this, RefreshDataCoreAsync));
_renderColumnHeaders = RenderColumnHeaders;
_renderNonVirtualizedRows = RenderNonVirtualizedRows;
// As a special case, we don't issue the first data load request until we've collected the initial set of columns
// This is so we can apply default sort order (or any future per-column options) before loading data
// We use EventCallbackSubscriber to safely hook this async operation into the synchronous rendering flow
var columnsFirstCollectedSubscriber = new EventCallbackSubscriber<object?>(
EventCallback.Factory.Create<object?>(this, RefreshDataCoreAsync));
columnsFirstCollectedSubscriber.SubscribeOrMove(_internalGridContext.ColumnsFirstCollected);
}
When RefreshDataCoreAsync is called the _virtualizeComponent
is still null and then the GridItemsProviderRequest.Count will be null:
private async Task RefreshDataCoreAsync()
{
// Move into a "loading" state, cancelling any earlier-but-still-pending load
_pendingDataLoadCancellationTokenSource?.Cancel();
var thisLoadCts = _pendingDataLoadCancellationTokenSource = new CancellationTokenSource();
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
await _virtualizeComponent.RefreshDataAsync();
_pendingDataLoadCancellationTokenSource = null;
}
else
{
// If we're not using Virtualize, we build and execute a request against the items provider directly
_lastRefreshedPaginationStateHash = Pagination?.GetHashCode();
var startIndex = Pagination is null ? 0 : (Pagination.CurrentPageIndex * Pagination.ItemsPerPage);
var request = new GridItemsProviderRequest<TGridItem>(
startIndex, Pagination?.ItemsPerPage, _sortByColumn, _sortByAscending, thisLoadCts.Token);
var result = await ResolveItemsRequestAsync(request);
if (!thisLoadCts.IsCancellationRequested)
{
_currentNonVirtualizedViewItems = result.Items;
_ariaBodyRowCount = _currentNonVirtualizedViewItems.Count;
Pagination?.SetTotalItemCountAsync(result.TotalItemCount);
_pendingDataLoadCancellationTokenSource = null;
}
}
}
The second call to the ItemsProvider comes from ProvideVirtualizedItems(ItemsProviderRequest request) and here the GridItemsProviderRequest.Count has a value.
Expected Behavior
When using "ItemsProvider" and "Virtualize"=true then the GridItemsProviderRequest.Count is never null.
Steps To Reproduce
Just use from code from the example "Filtering remote data":
https://aspnet.github.io/quickgridsamples/filtering/
Exceptions (if any)
No response
.NET Version
8.0.300
Anything else?
No response