Browse Source

Added a playground page to virtualization demo.

For testing selection, collection changes and scroll into view etc.
Steven Kirk 2 years ago
parent
commit
36444706c1

+ 5 - 4
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">
   <controls:HamburgerMenu>
-    <TabItem Header="Chat" >
+    <TabItem Header="Playground" ScrollViewer.VerticalScrollBarVisibility="Disabled">
+      <views:PlaygroundPageView DataContext="{Binding Playground}"/>
+    </TabItem>
+    <TabItem Header="Chat" ScrollViewer.VerticalScrollBarVisibility="Disabled">
       <views:ChatPageView DataContext="{Binding Chat}"/>
     </TabItem>
-    <TabItem Header="Expanders">
+    <TabItem Header="Expanders" ScrollViewer.VerticalScrollBarVisibility="Disabled">
       <views:ExpanderPageView DataContext="{Binding Expanders}"/>
     </TabItem>
   </controls:HamburgerMenu>

+ 1 - 1
samples/VirtualizationDemo/Models/Chat.cs

@@ -16,7 +16,7 @@ public class ChatFile
         };
 
         using var s = File.OpenRead(path);
-        return JsonSerializer.Deserialize<ChatFile>(s, options);
+        return JsonSerializer.Deserialize<ChatFile>(s, options)!;
     }
 }
 

+ 1 - 0
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();
 }

+ 17 - 0
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);
+    }
+}

+ 95 - 0
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<PlaygroundItemViewModel> 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<PlaygroundItemViewModel> 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;
+    }
+}

+ 66 - 0
samples/VirtualizationDemo/Views/PlaygroundPageView.axaml

@@ -0,0 +1,66 @@
+<UserControl xmlns="https://github.com/avaloniaui"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+             xmlns:vm="using:VirtualizationDemo.ViewModels"
+             mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+             x:Class="VirtualizationDemo.Views.PlaygroundPageView"
+             x:DataType="vm:PlaygroundPageViewModel">
+  <DockPanel>
+    <StackPanel DockPanel.Dock="Right" Margin="8 0" Width="200">
+      <DropDownButton Content="Selection" HorizontalAlignment="Stretch">
+        <Button.Flyout>
+          <Flyout>
+            <StackPanel>
+              <CheckBox IsChecked="{Binding Multiple}">Multiple</CheckBox>
+              <CheckBox IsChecked="{Binding Toggle}">Toggle</CheckBox>
+              <CheckBox IsChecked="{Binding AlwaysSelected}">AlwaysSelected</CheckBox>
+              <CheckBox IsChecked="{Binding #list.AutoScrollToSelectedItem}">AutoScrollToSelectedItem</CheckBox>
+              <CheckBox IsChecked="{Binding #list.WrapSelection}">WrapSelection</CheckBox>
+            </StackPanel>
+          </Flyout>
+        </Button.Flyout>
+      </DropDownButton>
+      
+      <Label>_Select Item</Label>
+      <DockPanel>
+        <TextBox x:Name="scrollToIndex" Text="{Binding ScrollToIndex}">
+          <TextBox.InnerRightContent>
+            <StackPanel Orientation="Horizontal">
+              <Button DockPanel.Dock="Right"
+                      Command="{Binding RandomizeScrollToIndex}"
+                      ToolTip.Tip="Randomize">
+                &#x27F3;
+              </Button>
+              <Button DockPanel.Dock="Right"
+                      Command="{Binding ExecuteScrollToIndex}"
+                      ToolTip.Tip="Execute">
+                &#11152;
+              </Button>
+            </StackPanel>
+          </TextBox.InnerRightContent>
+        </TextBox>
+      </DockPanel>
+
+      <Label>New Item</Label>
+      <TextBox Text="{Binding NewItemHeader}">
+        <TextBox.InnerRightContent>
+          <Button Command="{Binding AddAtSelectedIndex}"
+                  ToolTip.Tip="Add at Selected Index">&#x2B;</Button>
+        </TextBox.InnerRightContent>
+      </TextBox>
+
+      <Button Command="{Binding DeleteSelectedItem}" Margin="0 8 0 0">
+        Delete Selected
+      </Button>
+    </StackPanel>
+    
+    <TextBlock Name="itemCount" DockPanel.Dock="Bottom"/>
+    
+    <ListBox Name="list"
+             ItemsSource="{Binding Items}"
+             DisplayMemberBinding="{Binding Header}"
+             Selection="{Binding Selection}"
+             SelectionMode="{Binding SelectionMode}"/>
+  </DockPanel>
+</UserControl>

+ 44 - 0
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;
+    }
+}