diff --git a/samples/VirtualizationDemo/MainWindow.axaml b/samples/VirtualizationDemo/MainWindow.axaml
index e064e6ab32..04e75450bf 100644
--- a/samples/VirtualizationDemo/MainWindow.axaml
+++ b/samples/VirtualizationDemo/MainWindow.axaml
@@ -5,14 +5,15 @@
xmlns:views="using:VirtualizationDemo.Views"
x:Class="VirtualizationDemo.MainWindow"
Title="AvaloniaUI Virtualization Demo"
- Width="800"
- Height="600"
x:DataType="vm:MainWindowViewModel">
-
+
+
+
+
-
+
diff --git a/samples/VirtualizationDemo/Models/Chat.cs b/samples/VirtualizationDemo/Models/Chat.cs
index e84760135c..8a701cc454 100644
--- a/samples/VirtualizationDemo/Models/Chat.cs
+++ b/samples/VirtualizationDemo/Models/Chat.cs
@@ -16,7 +16,7 @@ public class ChatFile
};
using var s = File.OpenRead(path);
- return JsonSerializer.Deserialize(s, options);
+ return JsonSerializer.Deserialize(s, options)!;
}
}
diff --git a/samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs b/samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs
index 6432503595..478e40187e 100644
--- a/samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs
+++ b/samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs
@@ -4,6 +4,7 @@ namespace VirtualizationDemo.ViewModels;
internal class MainWindowViewModel : ViewModelBase
{
+ public PlaygroundPageViewModel Playground { get; } = new();
public ChatPageViewModel Chat { get; } = new();
public ExpanderPageViewModel Expanders { get; } = new();
}
diff --git a/samples/VirtualizationDemo/ViewModels/PlaygroundItemViewModel.cs b/samples/VirtualizationDemo/ViewModels/PlaygroundItemViewModel.cs
new file mode 100644
index 0000000000..584ef4600b
--- /dev/null
+++ b/samples/VirtualizationDemo/ViewModels/PlaygroundItemViewModel.cs
@@ -0,0 +1,17 @@
+using MiniMvvm;
+
+namespace VirtualizationDemo.ViewModels;
+
+public class PlaygroundItemViewModel : ViewModelBase
+{
+ private string? _header;
+
+ public PlaygroundItemViewModel(int index) => Header = $"Item {index}";
+ public PlaygroundItemViewModel(string? header) => Header = header;
+
+ public string? Header
+ {
+ get => _header;
+ set => RaiseAndSetIfChanged(ref _header, value);
+ }
+}
diff --git a/samples/VirtualizationDemo/ViewModels/PlaygroundPageViewModel.cs b/samples/VirtualizationDemo/ViewModels/PlaygroundPageViewModel.cs
new file mode 100644
index 0000000000..98ab91b0a6
--- /dev/null
+++ b/samples/VirtualizationDemo/ViewModels/PlaygroundPageViewModel.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Collections.ObjectModel;
+using System.Linq;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.Selection;
+using MiniMvvm;
+
+namespace VirtualizationDemo.ViewModels;
+
+public class PlaygroundPageViewModel : ViewModelBase
+{
+ private SelectionMode _selectionMode = SelectionMode.Multiple;
+ private int _scrollToIndex = 500;
+ private string? _newItemHeader = "New Item 1";
+
+ public PlaygroundPageViewModel()
+ {
+ Items = new(Enumerable.Range(0, 1000).Select(x => new PlaygroundItemViewModel(x)));
+ Selection = new();
+ }
+
+ public ObservableCollection Items { get; }
+
+ public bool Multiple
+ {
+ get => _selectionMode.HasAnyFlag(SelectionMode.Multiple);
+ set => SetSelectionMode(SelectionMode.Multiple, value);
+ }
+
+ public bool Toggle
+ {
+ get => _selectionMode.HasAnyFlag(SelectionMode.Toggle);
+ set => SetSelectionMode(SelectionMode.Toggle, value);
+ }
+
+ public bool AlwaysSelected
+ {
+ get => _selectionMode.HasAnyFlag(SelectionMode.AlwaysSelected);
+ set => SetSelectionMode(SelectionMode.AlwaysSelected, value);
+ }
+
+ public SelectionModel Selection { get; }
+
+ public SelectionMode SelectionMode
+ {
+ get => _selectionMode;
+ set => RaiseAndSetIfChanged(ref _selectionMode, value);
+ }
+
+ public int ScrollToIndex
+ {
+ get => _scrollToIndex;
+ set => RaiseAndSetIfChanged(ref _scrollToIndex, value);
+ }
+
+ public string? NewItemHeader
+ {
+ get => _newItemHeader;
+ set => RaiseAndSetIfChanged(ref _newItemHeader, value);
+ }
+
+ public void ExecuteScrollToIndex()
+ {
+ Selection.Select(ScrollToIndex);
+ }
+
+ public void RandomizeScrollToIndex()
+ {
+ var rnd = new Random();
+ ScrollToIndex = rnd.Next(Items.Count);
+ }
+
+ public void AddAtSelectedIndex()
+ {
+ if (Selection.SelectedIndex == -1)
+ return;
+ Items.Insert(Selection.SelectedIndex, new(NewItemHeader));
+ }
+
+ public void DeleteSelectedItem()
+ {
+ var count = Selection.Count;
+ for (var i = count - 1; i >= 0; i--)
+ Items.RemoveAt(Selection.SelectedIndexes[i]);
+ }
+
+ private void SetSelectionMode(SelectionMode mode, bool value)
+ {
+ if (value)
+ SelectionMode |= mode;
+ else
+ SelectionMode &= ~mode;
+ }
+}
diff --git a/samples/VirtualizationDemo/Views/PlaygroundPageView.axaml b/samples/VirtualizationDemo/Views/PlaygroundPageView.axaml
new file mode 100644
index 0000000000..52bc6fd27a
--- /dev/null
+++ b/samples/VirtualizationDemo/Views/PlaygroundPageView.axaml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+ Multiple
+ Toggle
+ AlwaysSelected
+ AutoScrollToSelectedItem
+ WrapSelection
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/VirtualizationDemo/Views/PlaygroundPageView.axaml.cs b/samples/VirtualizationDemo/Views/PlaygroundPageView.axaml.cs
new file mode 100644
index 0000000000..5282475778
--- /dev/null
+++ b/samples/VirtualizationDemo/Views/PlaygroundPageView.axaml.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Linq;
+using System.Threading;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using Avalonia.Threading;
+
+namespace VirtualizationDemo.Views;
+
+public partial class PlaygroundPageView : UserControl
+{
+ private DispatcherTimer _timer;
+
+ public PlaygroundPageView()
+ {
+ InitializeComponent();
+
+ _timer = new DispatcherTimer
+ {
+ Interval = TimeSpan.FromMilliseconds(500),
+ };
+
+ _timer.Tick += TimerTick;
+ }
+
+ protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
+ {
+ base.OnAttachedToVisualTree(e);
+ _timer.Start();
+ }
+
+ protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
+ {
+ base.OnDetachedFromVisualTree(e);
+ _timer.Stop();
+ }
+
+ private void TimerTick(object? sender, EventArgs e)
+ {
+ var message = $"Realized {list.GetRealizedContainers().Count()} of {list.ItemsPanelRoot?.Children.Count}";
+ itemCount.Text = message;
+ }
+}