Skip to content

Commit 3da02fb

Browse files
Add public API for MaxItemCount
1 parent d306afc commit 3da02fb

File tree

6 files changed

+65
-29
lines changed

6 files changed

+65
-29
lines changed

src/Components/Web/src/PublicAPI.Unshipped.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,7 @@ Microsoft.AspNetCore.Components.Web.Internal.IInternalWebJSInProcessRuntime
33
Microsoft.AspNetCore.Components.Web.Internal.IInternalWebJSInProcessRuntime.InvokeJS(string! identifier, string? argsJson, Microsoft.JSInterop.JSCallResultType resultType, long targetInstanceId) -> string!
44
Microsoft.AspNetCore.Components.Web.KeyboardEventArgs.IsComposing.get -> bool
55
Microsoft.AspNetCore.Components.Web.KeyboardEventArgs.IsComposing.set -> void
6+
Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize<TItem>.MaxItemCount.get -> int
7+
Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize<TItem>.MaxItemCount.set -> void
68
override Microsoft.AspNetCore.Components.HtmlRendering.Infrastructure.StaticHtmlRenderer.RendererInfo.get -> Microsoft.AspNetCore.Components.RendererInfo!
79
override Microsoft.AspNetCore.Components.Routing.FocusOnNavigate.BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder! builder) -> void

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

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,6 @@ public sealed class Virtualize<TItem> : ComponentBase, IVirtualizeJsCallbacks, I
126126
[Parameter]
127127
public string SpacerElement { get; set; } = "div";
128128

129-
/*
130-
This API will be added in .NET 9 but cannot be added in a .NET 8 or earlier patch,
131-
as we can't change public API in patches.
132-
133129
/// <summary>
134130
/// Gets or sets the maximum number of items that will be rendered, even if the client reports
135131
/// that its viewport is large enough to show more. The default value is 100.
@@ -140,7 +136,6 @@ as we can't change public API in patches.
140136
/// </summary>
141137
[Parameter]
142138
public int MaxItemCount { get; set; } = 100;
143-
*/
144139

145140
/// <summary>
146141
/// Instructs the component to re-request data from its <see cref="ItemsProvider"/>.
@@ -356,12 +351,13 @@ private void CalcualteItemDistribution(
356351
_itemSize = ItemSize;
357352
}
358353

359-
// This AppContext data exists as a stopgap for .NET 8 and earlier, since this is being added in a patch
360-
// where we can't add new public API.
354+
// This AppContext data was added as a stopgap for .NET 8 and earlier, since it was added in a patch
355+
// where we couldn't add new public API. For backcompat we still support the AppContext setting, but
356+
// new applications should use the much more convenient MaxItemCount parameter.
361357
var maxItemCount = AppContext.GetData("Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize.MaxItemCount") switch
362358
{
363-
int val => val, // In .NET 9, this will be Math.Min(val, MaxItemCount)
364-
_ => 1000 // In .NET 9, this will be MaxItemCount
359+
int val => Math.Min(val, MaxItemCount),
360+
_ => MaxItemCount
365361
};
366362

367363
itemsInSpacer = Math.Max(0, (int)Math.Floor(spacerSize / _itemSize) - OverscanCount);

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

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -262,10 +262,21 @@ public void CanRenderHtmlTable()
262262
Assert.Contains(expectedInitialSpacerStyle, bottomSpacer.GetAttribute("style"));
263263
}
264264

265-
[Fact]
266-
public void CanLimitMaxItemsRendered()
265+
[Theory]
266+
[InlineData(true)]
267+
[InlineData(false)]
268+
public void CanLimitMaxItemsRendered(bool useAppContext)
267269
{
268-
Browser.MountTestComponent<VirtualizationMaxItemCount>();
270+
if (useAppContext)
271+
{
272+
// This is to test back-compat with the switch added in a .NET 8 patch.
273+
// Newer applications shouldn't use this technique.
274+
Browser.MountTestComponent<VirtualizationMaxItemCount_AppContext>();
275+
}
276+
else
277+
{
278+
Browser.MountTestComponent<VirtualizationMaxItemCount>();
279+
}
269280

270281
// Despite having a 600px tall scroll area and 30px high items (600/30=20),
271282
// we only render 10 items due to the MaxItemCount setting

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@
110110
<option value="BasicTestApp.VirtualizationComponent">Virtualization</option>
111111
<option value="BasicTestApp.VirtualizationDataChanges">Virtualization data changes</option>
112112
<option value="BasicTestApp.VirtualizationMaxItemCount">Virtualization MaxItemCount</option>
113+
<option value="BasicTestApp.VirtualizationMaxItemCount_AppContext">Virtualization MaxItemCount (via AppContext)</option>
113114
<option value="BasicTestApp.VirtualizationTable">Virtualization HTML table</option>
114115
<option value="BasicTestApp.HotReload.RenderOnHotReload">Render on hot reload</option>
115116
<option value="BasicTestApp.SectionsTest.ParentComponentWithTwoChildren">Sections test</option>
Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
@implements IDisposable
2-
<p>
1+
<p>
32
MaxItemCount is a safeguard against the client reporting a giant viewport and causing the server to perform a
43
correspondingly giant data load and then tracking a lot of render state.
54
</p>
@@ -12,23 +11,14 @@
1211
</p>
1312

1413
<div id="virtualize-scroll-area" style="height: 600px; overflow-y: scroll; outline: 1px solid red; background: #eee;">
15-
@* In .NET 8 and earlier, the E2E test uses an AppContext.SetData call to set MaxItemCount *@
16-
@* In .NET 9 onwards, it's a Virtualize component parameter *@
17-
<Virtualize ItemsProvider="GetItems" ItemSize="30">
14+
<Virtualize ItemsProvider="GetItems" ItemSize="30" MaxItemCount="10">
1815
<div class="my-item" @key="context" style="height: 30px; outline: 1px solid #ccc">
1916
Id: @context.Id; Name: @context.Name
2017
</div>
2118
</Virtualize>
2219
</div>
2320

2421
@code {
25-
protected override void OnInitialized()
26-
{
27-
// This relies on Xunit's default behavior of running tests in the same collection sequentially,
28-
// not in parallel. From .NET 9 onwards this can be removed in favour of a Virtualize parameter.
29-
AppContext.SetData("Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize.MaxItemCount", 10);
30-
}
31-
3222
private async ValueTask<ItemsProviderResult<MyThing>> GetItems(ItemsProviderRequest request)
3323
{
3424
const int numThings = 100000;
@@ -40,9 +30,4 @@
4030
}
4131

4232
record MyThing(int Id, string Name);
43-
44-
public void Dispose()
45-
{
46-
AppContext.SetData("Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize.MaxItemCount", null);
47-
}
4833
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
@implements IDisposable
2+
<p>
3+
This is a variation of the VirtualizationMaxItemCount test case in which the max count is set using AppContext.
4+
This E2E test exists only to verify back-compatibility.
5+
</p>
6+
7+
<div id="virtualize-scroll-area" style="height: 600px; overflow-y: scroll; outline: 1px solid red; background: #eee;">
8+
@* In .NET 8 and earlier, the E2E test uses an AppContext.SetData call to set MaxItemCount *@
9+
@* In .NET 9 onwards, it's a Virtualize component parameter *@
10+
<Virtualize ItemsProvider="GetItems" ItemSize="30">
11+
<div class="my-item" @key="context" style="height: 30px; outline: 1px solid #ccc">
12+
Id: @context.Id; Name: @context.Name
13+
</div>
14+
</Virtualize>
15+
</div>
16+
17+
@code {
18+
protected override void OnInitialized()
19+
{
20+
// This relies on Xunit's default behavior of running tests in the same collection sequentially,
21+
// not in parallel. From .NET 9 onwards this can be removed in favour of a Virtualize parameter.
22+
AppContext.SetData("Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize.MaxItemCount", 10);
23+
}
24+
25+
private async ValueTask<ItemsProviderResult<MyThing>> GetItems(ItemsProviderRequest request)
26+
{
27+
const int numThings = 100000;
28+
29+
await Task.Delay(100);
30+
return new ItemsProviderResult<MyThing>(
31+
Enumerable.Range(request.StartIndex, request.Count).Select(i => new MyThing(i, $"Thing {i}")),
32+
numThings);
33+
}
34+
35+
record MyThing(int Id, string Name);
36+
37+
public void Dispose()
38+
{
39+
AppContext.SetData("Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize.MaxItemCount", null);
40+
}
41+
}

0 commit comments

Comments
 (0)