From 50f7457e7aa9f304c18f64a36f825e7e08d1c320 Mon Sep 17 00:00:00 2001 From: Daria Tiurina Date: Wed, 5 Nov 2025 17:00:12 +0100 Subject: [PATCH 1/4] Implement E2E test --- .../test/E2ETest/Tests/QuickGridTest.cs | 31 +++++++++ .../test/testassets/BasicTestApp/Index.razor | 2 + .../QuickGridFilterComponent.razor | 68 +++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 src/Components/test/testassets/BasicTestApp/QuickGridTest/QuickGridFilterComponent.razor diff --git a/src/Components/test/E2ETest/Tests/QuickGridTest.cs b/src/Components/test/E2ETest/Tests/QuickGridTest.cs index 6b1c2f0713bf..312d2995203d 100644 --- a/src/Components/test/E2ETest/Tests/QuickGridTest.cs +++ b/src/Components/test/E2ETest/Tests/QuickGridTest.cs @@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures; using Microsoft.AspNetCore.E2ETesting; using OpenQA.Selenium; +using OpenQA.Selenium.Interactions; using OpenQA.Selenium.Support.Extensions; using Xunit.Abstractions; @@ -215,4 +216,34 @@ public void ItemsProviderCalledOnceWithVirtualize() app = Browser.MountTestComponent(); Browser.Equal("1", () => app.FindElement(By.Id("items-provider-call-count")).Text); } + + [Fact] + public void FilterUsingSetCurrentPageDoesNotCauseExtraRefresh() + { + app = Browser.MountTestComponent(); + + Browser.Equal("1", () => app.FindElement(By.Id("items-provider-calls")).Text); + + var filterInput = app.FindElement(By.Id("filter-input")); + filterInput.Clear(); + filterInput.SendKeys("Item 1"); + app.FindElement(By.Id("apply-filter-reset-pagination-btn")).Click(); + + Browser.Equal("2", () => app.FindElement(By.Id("items-provider-calls")).Text); + } + + [Fact] + public void FilterUsingRefreshDataDoesNotCauseExtraRefresh() + { + app = Browser.MountTestComponent(); + + Browser.Equal("1", () => app.FindElement(By.Id("items-provider-calls")).Text); + + var filterInput = app.FindElement(By.Id("filter-input")); + filterInput.Clear(); + filterInput.SendKeys("Item 1"); + app.FindElement(By.Id("apply-filter-refresh-data-btn")).Click(); + + Browser.Equal("2", () => app.FindElement(By.Id("items-provider-calls")).Text); + } } diff --git a/src/Components/test/testassets/BasicTestApp/Index.razor b/src/Components/test/testassets/BasicTestApp/Index.razor index f9cc718f7ca1..7d7a6281b1df 100644 --- a/src/Components/test/testassets/BasicTestApp/Index.razor +++ b/src/Components/test/testassets/BasicTestApp/Index.razor @@ -96,7 +96,9 @@ + + diff --git a/src/Components/test/testassets/BasicTestApp/QuickGridTest/QuickGridFilterComponent.razor b/src/Components/test/testassets/BasicTestApp/QuickGridTest/QuickGridFilterComponent.razor new file mode 100644 index 000000000000..17b0804ee41f --- /dev/null +++ b/src/Components/test/testassets/BasicTestApp/QuickGridTest/QuickGridFilterComponent.razor @@ -0,0 +1,68 @@ +@using Microsoft.AspNetCore.Components.QuickGrid + +
+ + + +
+ +
+ + + + +
+ + +

@itemsProviderCalls

+ +@code { + PaginationState pagination = new PaginationState { ItemsPerPage = 5 }; + int itemsProviderCalls = 0; + GridItemsProvider itemsProvider; + QuickGrid gridRef; + string filter = string.Empty; + + private readonly List allItems = Enumerable.Range(1, 25) + .Select(i => new Item { Id = i, Name = $"Item {i}" }) + .ToList(); + + protected override void OnInitialized() + { + itemsProvider = async request => + { + await Task.CompletedTask; + + itemsProviderCalls++; + StateHasChanged(); + + var filteredItems = string.IsNullOrEmpty(filter) + ? allItems + : allItems.Where(i => i.Name.Contains(filter, StringComparison.OrdinalIgnoreCase)).ToList(); + + var totalCount = filteredItems.Count; + var pagedItems = filteredItems + .Skip(request.StartIndex) + .Take(request.Count ?? 5) + .ToList(); + + return GridItemsProviderResult.From(pagedItems, totalCount); + }; + } + + protected async Task ApplyFilterResetPagination() + { + await pagination.SetCurrentPageIndexAsync(0); + } + + protected async Task ApplyFilterRefreshData() + { + await gridRef.RefreshDataAsync(); + } + + class Item + { + public int Id { get; set; } + public string Name { get; set; } = string.Empty; + } +} From 345a8b1fd62540000af1ad27d24c9472b55430f3 Mon Sep 17 00:00:00 2001 From: Daria Tiurina Date: Fri, 5 Dec 2025 11:14:23 +0100 Subject: [PATCH 2/4] Implement fix --- .../src/QuickGrid.razor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/QuickGrid.razor.cs b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/QuickGrid.razor.cs index 28729c2eb58d..761b26d72259 100644 --- a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/QuickGrid.razor.cs +++ b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/QuickGrid.razor.cs @@ -335,7 +335,6 @@ private async Task RefreshDataCoreAsync() 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( startIndex, Pagination?.ItemsPerPage, _sortByColumn, _sortByAscending, thisLoadCts.Token); @@ -347,6 +346,7 @@ private async Task RefreshDataCoreAsync() Pagination?.SetTotalItemCountAsync(result.TotalItemCount); _pendingDataLoadCancellationTokenSource = null; } + _lastRefreshedPaginationStateHash = Pagination?.GetHashCode(); } } From e8acdfdfda34e7c5bbbe0e8c7d6f59672171f530 Mon Sep 17 00:00:00 2001 From: Daria Tiurina Date: Fri, 5 Dec 2025 11:18:22 +0100 Subject: [PATCH 3/4] Clean-up --- src/Components/test/E2ETest/Tests/QuickGridTest.cs | 1 - src/Components/test/testassets/BasicTestApp/Index.razor | 1 - 2 files changed, 2 deletions(-) diff --git a/src/Components/test/E2ETest/Tests/QuickGridTest.cs b/src/Components/test/E2ETest/Tests/QuickGridTest.cs index 312d2995203d..7523d93c853d 100644 --- a/src/Components/test/E2ETest/Tests/QuickGridTest.cs +++ b/src/Components/test/E2ETest/Tests/QuickGridTest.cs @@ -8,7 +8,6 @@ using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures; using Microsoft.AspNetCore.E2ETesting; using OpenQA.Selenium; -using OpenQA.Selenium.Interactions; using OpenQA.Selenium.Support.Extensions; using Xunit.Abstractions; diff --git a/src/Components/test/testassets/BasicTestApp/Index.razor b/src/Components/test/testassets/BasicTestApp/Index.razor index 7d7a6281b1df..9a89e61146b2 100644 --- a/src/Components/test/testassets/BasicTestApp/Index.razor +++ b/src/Components/test/testassets/BasicTestApp/Index.razor @@ -96,7 +96,6 @@ - From 7ff916481ca8438a3fb7e99bbdf6ae6dff259365 Mon Sep 17 00:00:00 2001 From: Daria Tiurina Date: Fri, 5 Dec 2025 12:37:57 +0100 Subject: [PATCH 4/4] Clean-up and fix --- .../src/QuickGrid.razor.cs | 2 +- .../BasicTestApp/QuickGridTest/QuickGridFilterComponent.razor | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/QuickGrid.razor.cs b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/QuickGrid.razor.cs index 761b26d72259..395ec58777c9 100644 --- a/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/QuickGrid.razor.cs +++ b/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/QuickGrid.razor.cs @@ -344,9 +344,9 @@ private async Task RefreshDataCoreAsync() _currentNonVirtualizedViewItems = result.Items; _ariaBodyRowCount = _currentNonVirtualizedViewItems.Count; Pagination?.SetTotalItemCountAsync(result.TotalItemCount); + _lastRefreshedPaginationStateHash = Pagination?.GetHashCode(); _pendingDataLoadCancellationTokenSource = null; } - _lastRefreshedPaginationStateHash = Pagination?.GetHashCode(); } } diff --git a/src/Components/test/testassets/BasicTestApp/QuickGridTest/QuickGridFilterComponent.razor b/src/Components/test/testassets/BasicTestApp/QuickGridTest/QuickGridFilterComponent.razor index 17b0804ee41f..7b0414e4c2f1 100644 --- a/src/Components/test/testassets/BasicTestApp/QuickGridTest/QuickGridFilterComponent.razor +++ b/src/Components/test/testassets/BasicTestApp/QuickGridTest/QuickGridFilterComponent.razor @@ -19,7 +19,7 @@ @code { PaginationState pagination = new PaginationState { ItemsPerPage = 5 }; int itemsProviderCalls = 0; - GridItemsProvider itemsProvider; + GridItemsProvider itemsProvider = default!; QuickGrid gridRef; string filter = string.Empty; @@ -33,7 +33,7 @@ { await Task.CompletedTask; - itemsProviderCalls++; + Interlocked.Increment(ref itemsProviderCalls); StateHasChanged(); var filteredItems = string.IsNullOrEmpty(filter)