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:
+
+
+
Viewport as root: