Skip to content

Commit e43041d

Browse files
Make Virtualize recover from having incorrect ItemSize info. Fixes #25915 (#26933)
1 parent 5f2390b commit e43041d

File tree

3 files changed

+55
-0
lines changed

3 files changed

+55
-0
lines changed

src/Components/Web/src/Virtualization/Virtualize.cs

+18
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,15 @@ void IVirtualizeJsCallbacks.OnBeforeSpacerVisible(float spacerSize, float spacer
253253
{
254254
CalcualteItemDistribution(spacerSize, spacerSeparation, containerSize, out var itemsBefore, out var visibleItemCapacity);
255255

256+
// Since we know the before spacer is now visible, we absolutely have to slide the window up
257+
// by at least one element. If we're not doing that, the previous item size info we had must
258+
// have been wrong, so just move along by one in that case to trigger an update and apply the
259+
// new size info.
260+
if (itemsBefore == _itemsBefore && itemsBefore > 0)
261+
{
262+
itemsBefore--;
263+
}
264+
256265
UpdateItemDistribution(itemsBefore, visibleItemCapacity);
257266
}
258267

@@ -262,6 +271,15 @@ void IVirtualizeJsCallbacks.OnAfterSpacerVisible(float spacerSize, float spacerS
262271

263272
var itemsBefore = Math.Max(0, _itemCount - itemsAfter - visibleItemCapacity);
264273

274+
// Since we know the after spacer is now visible, we absolutely have to slide the window down
275+
// by at least one element. If we're not doing that, the previous item size info we had must
276+
// have been wrong, so just move along by one in that case to trigger an update and apply the
277+
// new size info.
278+
if (itemsBefore == _itemsBefore && itemsBefore < _itemCount - visibleItemCapacity)
279+
{
280+
itemsBefore++;
281+
}
282+
265283
UpdateItemDistribution(itemsBefore, visibleItemCapacity);
266284
}
267285

src/Components/test/E2ETest/Tests/VirtualizationTest.cs

+28
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System.Linq;
5+
using System.Threading.Tasks;
56
using BasicTestApp;
67
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
78
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
@@ -211,6 +212,33 @@ public void CanUseViewportAsContainer()
211212
Browser.NotEqual(expectedInitialSpacerStyle, () => topSpacer.GetAttribute("style"));
212213
}
213214

215+
[Fact]
216+
public async Task ToleratesIncorrectItemSize()
217+
{
218+
Browser.MountTestComponent<VirtualizationComponent>();
219+
var topSpacer = Browser.Exists(By.Id("incorrect-size-container")).FindElement(By.TagName("div"));
220+
var expectedInitialSpacerStyle = "height: 0px;";
221+
222+
// Wait until items have been rendered.
223+
Browser.True(() => GetItemCount() > 0);
224+
Browser.Equal(expectedInitialSpacerStyle, () => topSpacer.GetAttribute("style"));
225+
226+
// Scroll slowly, in increments of 50px at a time. At one point this would trigger a bug
227+
// due to the incorrect item size, whereby it would not realise it's necessary to show more
228+
// items because the first time the spacer became visible, the size calculation said that
229+
// we're already showing all the items we need to show.
230+
for (var pos = 0; pos < 1000; pos += 50)
231+
{
232+
Browser.ExecuteJavaScript($"document.getElementById('incorrect-size-container').scrollTop = {pos};");
233+
await Task.Delay(200);
234+
}
235+
236+
// Validate that the top spacer did change
237+
Browser.NotEqual(expectedInitialSpacerStyle, () => topSpacer.GetAttribute("style"));
238+
239+
int GetItemCount() => Browser.FindElements(By.ClassName("incorrect-size-item")).Count;
240+
}
241+
214242
[Fact]
215243
public void CanMutateDataInPlace_Sync()
216244
{

src/Components/test/testassets/BasicTestApp/VirtualizationComponent.razor

+9
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@
2828
</div>
2929
</p>
3030

31+
<p>
32+
Slightly incorrect item size:<br />
33+
<div id="incorrect-size-container" style="background-color: #eee; height: 500px; overflow-y: auto">
34+
<Virtualize Items="@fixedItems" ItemSize="50">
35+
<div @key="context" class="incorrect-size-item" style="height: 49px; background-color: rgb(@((context % 2) * 255), @((1-(context % 2)) * 255), 255);">Item @context</div>
36+
</Virtualize>
37+
</div>
38+
</p>
39+
3140
<p id="viewport-as-root">
3241
Viewport as root:<br />
3342
<Virtualize Items="@fixedItems" ItemSize="itemSize">

0 commit comments

Comments
 (0)