There is no efficient way to change the items in Virtualize. Natural way to do it would be for Virtualize to respond to Items property change. Currently it does not respond.
Inefficient way is to update the @key for Virtualize . That approach causes flickering and resets the scrolling position.
In the announcement Virtualize is advertized as a replacement of inefficient foreach. This bug makes the replacement impossible in some situations.
Click "Add item". Virtualized list does not update. Non virtualized does.
In general, one would expect the virtualized and not virtualized versions to behave identically, for example, when it comes to preservation of scrolling position and when items are added/changed/removed.
@page "/"
@using System.Linq
Virtualized:
<div style="overflow-y: auto; height: 200px; border: 2px solid blue;">
<Virtualize Items="@items" Context="item" @key="@revision">
<div @key="@item">@item</div>
</Virtualize>
</div>
Not Virtualized:
<div style="overflow-y: auto; height: 200px; border: 2px solid blue;">
@foreach (var item in items)
{
<div @key="@item">@item</div>
}
</div>
<button @onclick="AddItem">Add item</button>
<button @onclick="AddItemAndUpdateKey">Add item and update Virtualize's key</button>
@code {
int[] items = Enumerable.Range(0, 5).ToArray();
int revision = 0;
void AddItem()
{
items = Enumerable.Range(0, items.Length + 1).ToArray();
}
void AddItemAndUpdateKey()
{
AddItem();
++revision;
}
}
$ dotnet --info
.NET SDK (reflecting any global.json):
Version: 5.0.100-rc.1.20452.10
Commit: 473d1b592e
Runtime Environment:
OS Name: Windows
OS Version: 10.0.19041
OS Platform: Windows
RID: win10-x64
Base Path: C:\Program Files\dotnet\sdk\5.0.100-rc.1.20452.10\
Host (useful for support):
Version: 5.0.0-rc.1.20451.14
Commit: 38017c3935
.NET SDKs installed:
2.1.202 [C:\Program Files\dotnet\sdk]
2.1.500 [C:\Program Files\dotnet\sdk]
2.1.503 [C:\Program Files\dotnet\sdk]
2.1.509 [C:\Program Files\dotnet\sdk]
2.1.515 [C:\Program Files\dotnet\sdk]
2.1.517 [C:\Program Files\dotnet\sdk]
2.2.105 [C:\Program Files\dotnet\sdk]
2.2.110 [C:\Program Files\dotnet\sdk]
3.0.100 [C:\Program Files\dotnet\sdk]
3.1.301 [C:\Program Files\dotnet\sdk]
3.1.401 [C:\Program Files\dotnet\sdk]
5.0.100-preview.7.20366.6 [C:\Program Files\dotnet\sdk]
5.0.100-preview.8.20417.9 [C:\Program Files\dotnet\sdk]
5.0.100-rc.1.20452.10 [C:\Program Files\dotnet\sdk]
.NET runtimes installed:
Microsoft.AspNetCore.All 2.1.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.All 2.1.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.All 2.1.13 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.All 2.1.19 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.All 2.1.21 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.All 2.2.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.All 2.2.8 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.App 2.1.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 2.1.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 2.1.13 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 2.1.19 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 2.1.21 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 2.2.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 2.2.8 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 3.1.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 3.1.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 5.0.0-preview.8.20414.8 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 5.0.0-rc.1.20451.17 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 2.0.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.1.6 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.1.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.1.13 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.1.19 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.1.21 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.2.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.2.8 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 3.1.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 3.1.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 5.0.0-preview.7.20364.11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 5.0.0-preview.8.20407.11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 5.0.0-rc.1.20451.14 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 3.1.5 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 3.1.7 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 5.0.0-preview.7.20366.1 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 5.0.0-preview.8.20411.6 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 5.0.0-rc.1.20452.2 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
To install additional .NET runtimes or SDKs:
https://aka.ms/dotnet-download
Thanks for contacting us. This is a dupe of https://github.com/dotnet/aspnetcore/issues/25899
The proposed fix with StateHasChanged() does not work.
Even if it did work, it would be only a workaround, not a proper fix. The way parent component notifies its children about a change is by re-rendering it with new properties. Smart child component, like Virtualize, has to override OnParametersSet to implement its side-effects.
Screenshot

Modified code
@page "/"
@using System.Linq
Virtualized:
<div style="overflow-y: auto; height: 200px; border: 2px solid blue;">
<Virtualize Items="@items" Context="item" @key="@revision">
<div @key="@item">@item</div>
</Virtualize>
</div>
Not Virtualized:
<div style="overflow-y: auto; height: 200px; border: 2px solid blue;">
@foreach (var item in items)
{
<div @key="@item">@item</div>
}
</div>
<button @onclick="AddItem">Add item</button>
<button @onclick="AddItemAndUpdateKey">Add item and update Virtualize's key</button>
@code {
int[] items = Enumerable.Range(0, 5).ToArray();
int revision = 0;
void AddItem()
{
items = Enumerable.Range(0, items.Length + 1).ToArray();
StateHasChanged(); // <-- added
}
void AddItemAndUpdateKey()
{
AddItem();
++revision;
}
}
Apologies that we misunderstood this the first time you posted it. I agree it's a real issue. Reopening.
@dotnet/aspnet-blazor-eng This is a pretty problematic limitation in <Virtualize>. As it stands, there's no way for the developer to tell the <Virtualize> component to re-request data from the ItemsProvider. So,
ItemsProvider's output completely (for example, by re-querying an external JSON service to get new data) then you have no way of making it do that. Only when the user scrolls away and then scrolls back will they be able to see updated data.Proposed solution
Items to supply a fixed set of synchronously-available in-memory data, we should update the internal "item count" info as part of each render cycle, since we know there's no cost involved in doing so. Then the original problem reported in this issue would go away immediately without the developer having to write any special code.ItemsProvider, we should add a new public async Task RefreshDataAsync method on Virtualize<TItem>. Developers can call this if they have reason to think the underlying data source output may have changed, for example when a user clicks a "Refresh" button. This would just do the same thing that happens when the user scrolls into a new set of data.I know RC2 is later for adding features, but the whole point of including <Virtualize> in RC1 was to get customer feedback on its usability. Now we have some important feedback, we should act on it, right? cc @danroth27 @mkArtakMSFT
Seems good to me. Can you prepare a PR? We could try and get this thru ask mode
Yes. Putting in RC2 milestone. @mkArtakMSFT please speak up if you have any concerns with this.
No concerns from me, @SteveSandersonMS! Please go ahead with a PR, but we need to rush. Time is running out.
I have a question regarding the PR that fixes this:
https://github.com/dotnet/aspnetcore/pull/26177/files#diff-18b60327e5f9093f24b96ed344268589R101-R107 mentions how it's not necessary to call the Refresh method when using Items instead of an items provider.
Yet, https://github.com/dotnet/aspnetcore/pull/26177/files#diff-18b60327e5f9093f24b96ed344268589R312-R314 talks about how it's also usable when using a static list of items.
Are the docs ambiguous or is it just my failed understanding?
The reason why it's not necessary for you to call RefreshDataAsync when using Items is that the framework does it for you automatically. That's why the internals of RefreshDataAsync do need to be concerned with this scenario, but you (the application developer) don't 馃槃
Most helpful comment
@dotnet/aspnet-blazor-eng This is a pretty problematic limitation in
<Virtualize>. As it stands, there's no way for the developer to tell the<Virtualize>component to re-request data from theItemsProvider. So,ItemsProvider's output completely (for example, by re-querying an external JSON service to get new data) then you have no way of making it do that. Only when the user scrolls away and then scrolls back will they be able to see updated data.Proposed solution
Itemsto supply a fixed set of synchronously-available in-memory data, we should update the internal "item count" info as part of each render cycle, since we know there's no cost involved in doing so. Then the original problem reported in this issue would go away immediately without the developer having to write any special code.ItemsProvider, we should add a newpublic async Task RefreshDataAsyncmethod onVirtualize<TItem>. Developers can call this if they have reason to think the underlying data source output may have changed, for example when a user clicks a "Refresh" button. This would just do the same thing that happens when the user scrolls into a new set of data.I know RC2 is later for adding features, but the whole point of including
<Virtualize>in RC1 was to get customer feedback on its usability. Now we have some important feedback, we should act on it, right? cc @danroth27 @mkArtakMSFT