From e43041d75fc9f190441cb6f8e5bd57776103caec Mon Sep 17 00:00:00 2001 From: Steve Sanderson Date: Thu, 15 Oct 2020 23:39:09 +0100 Subject: [PATCH] Make Virtualize recover from having incorrect ItemSize info. Fixes #25915 (#26933) --- .../Web/src/Virtualization/Virtualize.cs | 18 ++++++++++++ .../test/E2ETest/Tests/VirtualizationTest.cs | 28 +++++++++++++++++++ .../VirtualizationComponent.razor | 9 ++++++ 3 files changed, 55 insertions(+) diff --git a/src/Components/Web/src/Virtualization/Virtualize.cs b/src/Components/Web/src/Virtualization/Virtualize.cs index ec39b20818..3a99973768 100644 --- a/src/Components/Web/src/Virtualization/Virtualize.cs +++ b/src/Components/Web/src/Virtualization/Virtualize.cs @@ -253,6 +253,15 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization { CalcualteItemDistribution(spacerSize, spacerSeparation, containerSize, out var itemsBefore, out var visibleItemCapacity); + // Since we know the before spacer is now visible, we absolutely have to slide the window up + // by at least one element. If we're not doing that, the previous item size info we had must + // have been wrong, so just move along by one in that case to trigger an update and apply the + // new size info. + if (itemsBefore == _itemsBefore && itemsBefore > 0) + { + itemsBefore--; + } + UpdateItemDistribution(itemsBefore, visibleItemCapacity); } @@ -262,6 +271,15 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization var itemsBefore = Math.Max(0, _itemCount - itemsAfter - visibleItemCapacity); + // Since we know the after spacer is now visible, we absolutely have to slide the window down + // by at least one element. If we're not doing that, the previous item size info we had must + // have been wrong, so just move along by one in that case to trigger an update and apply the + // new size info. + if (itemsBefore == _itemsBefore && itemsBefore < _itemCount - visibleItemCapacity) + { + itemsBefore++; + } + UpdateItemDistribution(itemsBefore, visibleItemCapacity); } diff --git a/src/Components/test/E2ETest/Tests/VirtualizationTest.cs b/src/Components/test/E2ETest/Tests/VirtualizationTest.cs index f047bbb002..1bbf45d903 100644 --- a/src/Components/test/E2ETest/Tests/VirtualizationTest.cs +++ b/src/Components/test/E2ETest/Tests/VirtualizationTest.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Linq; +using System.Threading.Tasks; using BasicTestApp; using Microsoft.AspNetCore.Components.E2ETest.Infrastructure; using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures; @@ -211,6 +212,33 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests Browser.NotEqual(expectedInitialSpacerStyle, () => topSpacer.GetAttribute("style")); } + [Fact] + public async Task ToleratesIncorrectItemSize() + { + Browser.MountTestComponent(); + var topSpacer = Browser.Exists(By.Id("incorrect-size-container")).FindElement(By.TagName("div")); + var expectedInitialSpacerStyle = "height: 0px;"; + + // Wait until items have been rendered. + Browser.True(() => GetItemCount() > 0); + Browser.Equal(expectedInitialSpacerStyle, () => topSpacer.GetAttribute("style")); + + // Scroll slowly, in increments of 50px at a time. At one point this would trigger a bug + // due to the incorrect item size, whereby it would not realise it's necessary to show more + // items because the first time the spacer became visible, the size calculation said that + // we're already showing all the items we need to show. + for (var pos = 0; pos < 1000; pos += 50) + { + Browser.ExecuteJavaScript($"document.getElementById('incorrect-size-container').scrollTop = {pos};"); + await Task.Delay(200); + } + + // Validate that the top spacer did change + Browser.NotEqual(expectedInitialSpacerStyle, () => topSpacer.GetAttribute("style")); + + int GetItemCount() => Browser.FindElements(By.ClassName("incorrect-size-item")).Count; + } + [Fact] public void CanMutateDataInPlace_Sync() { diff --git a/src/Components/test/testassets/BasicTestApp/VirtualizationComponent.razor b/src/Components/test/testassets/BasicTestApp/VirtualizationComponent.razor index 69e776ccfd..de2ceed03a 100644 --- a/src/Components/test/testassets/BasicTestApp/VirtualizationComponent.razor +++ b/src/Components/test/testassets/BasicTestApp/VirtualizationComponent.razor @@ -28,6 +28,15 @@

+

+ Slightly incorrect item size:
+

+ +
Item @context
+
+
+

+

Viewport as root: