Data virtualization #18811
-
I'd like to use Avalonia to create a UI that may need to show millions of items. I can calculate upfront how many items there will be, but I'd like to load each on demand and I don't want the UI to try and enumerate them I know some of the controls do control virtualization, but is there a concept of data virtualization or do i need to create this myself? |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 4 replies
-
Not sure if this will be useful, but I think you should take a look at Bea Stollnitz blog and now made a GitHub repo. Bea's stuff: https://github.com/bstollnitz/old-wpf-blog HTH |
Beta Was this translation helpful? Give feedback.
-
You can check out The demo uses https://github.com/wieslawsoltes/DataBox is a bit more focused use case, especially with its But in general if you aren't using libraries, yes. You'll need to create a collection type that is virtualized. You won't be able to use |
Beta Was this translation helpful? Give feedback.
-
I would propose use a ListBox as it supports Virtualization. You could perform the initialization or loading of the items on their first usage. <Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:HugeLazyList.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="HugeLazyList.Views.MainWindow"
x:DataType="vm:MainWindowViewModel"
Icon="/Assets/avalonia-logo.ico"
Title="HugeLazyList">
<ScrollViewer
HorizontalScrollBarVisibility="Disabled">
<ListBox
ItemsSource="{Binding Items}"
SelectedItem="{Binding SelectedItem}"
AutoScrollToSelectedItem="True"
UseLayoutRounding="True">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid
ColumnDefinitions="1*, 1*">
<TextBlock
Grid.Column="0"
Text="{Binding MyProperty, Mode=OneWay}"/>
<TextBlock
Grid.Column="1"
Text="{Binding MyAsyncProperty^, FallbackValue='Loading...', Mode=OneWay}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>
</Window> using DynamicData.Binding;
using ReactiveUI;
using System;
using System.Threading.Tasks;
namespace HugeLazyList.ViewModels
{
public class MyListItem(int Id) : ReactiveObject
// Note: ReactiveObject is a relatively big base class.
// If there will be a huge number of instances prefer inheriting from INotifyPropertyChanged directly.
{
private string _MyProperty = null;
// MyProperty will be initalized and stored on the first access
public string MyProperty => _MyProperty ??= InitalizeMyProperty();
private string InitalizeMyProperty() => $"{Id}: Hello from MyProperty";
private string _MyAsyncProperty = null;
// MyAsyncProperty will be initalized and stored on the first access
public Task<string> MyAsyncProperty => _MyAsyncProperty is not null ? Task.Run(() => _MyAsyncProperty) : InitalizeMyAsyncProperty();
// simulate a time intensitive task
private Task<string> InitalizeMyAsyncProperty() => Task.Delay(2000).ContinueWith(oldTask =>
{
// use a lock if needed
_MyAsyncProperty = $"{Id}: Hello from MyAsyncProperty";
return _MyAsyncProperty;
});
}
public class MainWindowViewModel : ViewModelBase
{
// If there will be a huge number of items you might prefer ObservableCollectionExtended over ObservableCollection
public ObservableCollectionExtended<MyListItem> Items { get; } = [];
private MyListItem _SelectedItem;
public MyListItem SelectedItem
{
get => _SelectedItem;
set => this.RaiseAndSetIfChanged(ref _SelectedItem, value);
}
public MainWindowViewModel()
{
// This will trigger only one Reset event when leaving the scope instead of many Add events für every single item
using IDisposable notificationSuspender = Items.SuspendNotifications();
for (int i = 0; i < 1_000_000; i++)
{
MyListItem item = new(i);
Items.Add(item);
}
}
}
} It looks like this: HugeLazyList.2025-05-10.12-04-44.mp4The example app: |
Beta Was this translation helpful? Give feedback.
You can check out
ModelFlow
for ideas: https://github.com/ModelFlow-NET/ModelFlowThe demo uses
TreeDataGrid
,ListBox
, andComboBox
though there aren't any docs.https://github.com/wieslawsoltes/DataBox is a bit more focused use case, especially with its
VirtualPanel.ItemHeight
which can really speed up accurate layout for cases where every row is the same fixed height.But in general if you aren't using libraries, yes. You'll need to create a collection type that is virtualized. You won't be able to use
ObservableCollection
in any direct way, but you might be able to use placeholder factories if your total size isn't in the tens of millions. They can't be lazy on indexing though because …