Просмотр исходного кода

Allow changing virtualization mode in test app.

Not yet working correctly.
Steven Kirk 9 лет назад
Родитель
Сommit
ae2ea31c6e

+ 4 - 1
samples/VirtualizationTest/MainWindow.xaml

@@ -5,6 +5,8 @@
                     Margin="16 0 0 0" 
                     MinWidth="150"
                     Gap="4">
+            <DropDown Items="{Binding VirtualizationModes}"
+                      SelectedItem="{Binding VirtualizationMode}"/>
             <TextBox Watermark="Item Count"
                      UseFloatingWatermark="True"
                      Text="{Binding ItemCount}"/>
@@ -28,7 +30,8 @@
         <ListBox Name="listBox" 
                  Items="{Binding Items}" 
                  SelectedItems="{Binding SelectedItems}"
-                 SelectionMode="Multiple">
+                 SelectionMode="Multiple"
+                 VirtualizationMode="{Binding VirtualizationMode}">
             <ListBox.ItemTemplate>
                 <DataTemplate>
                     <TextBlock Text="{Binding Header}"/>

+ 12 - 0
samples/VirtualizationTest/ViewModels/MainWindowViewModel.cs

@@ -2,8 +2,10 @@
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 using System;
+using System.Collections.Generic;
 using System.Linq;
 using Avalonia.Collections;
+using Avalonia.Controls;
 using ReactiveUI;
 
 namespace VirtualizationTest.ViewModels
@@ -15,6 +17,7 @@ namespace VirtualizationTest.ViewModels
         private int _newItemIndex;
         private IReactiveList<ItemViewModel> _items;
         private string _prefix = "Item";
+        private ItemVirtualizationMode _virtualizationMode = ItemVirtualizationMode.Simple;
 
         public MainWindowViewModel()
         {
@@ -50,6 +53,15 @@ namespace VirtualizationTest.ViewModels
             private set { this.RaiseAndSetIfChanged(ref _items, value); }
         }
 
+        public ItemVirtualizationMode VirtualizationMode
+        {
+            get { return _virtualizationMode; }
+            set { this.RaiseAndSetIfChanged(ref _virtualizationMode, value); }
+        }
+
+        public IEnumerable<ItemVirtualizationMode> VirtualizationModes => 
+            Enum.GetValues(typeof(ItemVirtualizationMode)).Cast<ItemVirtualizationMode>();
+
         public ReactiveCommand<object> AddItemCommand { get; private set; }
 
         public ReactiveCommand<object> RecreateCommand { get; private set; }

+ 11 - 1
src/Avalonia.Controls/Presenters/ItemVirtualizer.cs

@@ -14,8 +14,10 @@ namespace Avalonia.Controls.Presenters
     /// <summary>
     /// Base class for classes which handle virtualization for an <see cref="ItemsPresenter"/>.
     /// </summary>
-    internal abstract class ItemVirtualizer : IVirtualizingController
+    internal abstract class ItemVirtualizer : IVirtualizingController, IDisposable
     {
+        private bool disposedValue;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="ItemVirtualizer"/> class.
         /// </summary>
@@ -181,6 +183,14 @@ namespace Avalonia.Controls.Presenters
             return false;
         }
 
+        /// <inheritdoc/>
+        public virtual void Dispose()
+        {
+            VirtualizingPanel.Controller = null;
+            VirtualizingPanel.Children.Clear();
+            Owner.ItemContainerGenerator.Clear();
+        }
+
         /// <summary>
         /// Invalidates the current scroll.
         /// </summary>

+ 18 - 0
src/Avalonia.Controls/Presenters/ItemsPresenter.cs

@@ -32,6 +32,9 @@ namespace Avalonia.Controls.Presenters
             KeyboardNavigation.TabNavigationProperty.OverrideDefaultValue(
                 typeof(ItemsPresenter),
                 KeyboardNavigationMode.Once);
+
+            VirtualizationModeProperty.Changed
+                .AddClassHandler<ItemsPresenter>(x => x.VirtualizationModeChanged);
         }
 
         /// <summary>
@@ -113,5 +116,20 @@ namespace Avalonia.Controls.Presenters
             var maxY = Math.Max(scrollable.Extent.Height - scrollable.Viewport.Height, 0);
             return new Vector(Clamp(value.X, 0, maxX), Clamp(value.Y, 0, maxY));
         }
+
+        private void VirtualizationModeChanged(AvaloniaPropertyChangedEventArgs e)
+        {
+            _virtualizer?.Dispose();
+            _virtualizer = ItemVirtualizer.Create(this);
+
+            if (Items != null && Panel != null)
+            {
+                _virtualizer.ItemsChanged(
+                    Items,
+                    new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
+            }
+
+            ((ILogicalScrollable)this).InvalidateScroll?.Invoke();
+        }
     }
 }

+ 35 - 0
tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization.cs

@@ -59,6 +59,20 @@ namespace Avalonia.Controls.UnitTests.Presenters
             Assert.True(((ILogicalScrollable)target).IsLogicalScrollEnabled);
         }
 
+        [Fact]
+        public void Parent_ScrollContentPresenter_Properties_Should_Be_Set()
+        {
+            var target = CreateTarget();
+
+            target.ApplyTemplate();
+            target.Measure(new Size(100, 100));
+            target.Arrange(new Rect(0, 0, 100, 100));
+
+            var scroll = (ScrollContentPresenter)target.Parent;
+            Assert.Equal(new Size(0, 20), scroll.Extent);
+            Assert.Equal(new Size(0, 10), scroll.Viewport);
+        }
+
         [Fact]
         public void Should_Fill_Panel_With_Containers()
         {
@@ -138,6 +152,27 @@ namespace Avalonia.Controls.UnitTests.Presenters
             }
         }
 
+        [Fact]
+        public void Changing_VirtualizationMode_Simple_To_None_Should_Update_Scroll_Properties()
+        {
+            var target = CreateTarget();
+
+            target.ApplyTemplate();
+            target.Measure(new Size(100, 100));
+            target.Arrange(new Rect(0, 0, 100, 100));
+
+            var scroll = (ScrollContentPresenter)target.Parent;
+            Assert.Equal(10, target.Panel.Children.Count);
+            Assert.Equal(new Size(0, 20), scroll.Extent);
+            Assert.Equal(new Size(0, 10), scroll.Viewport);
+
+            target.VirtualizationMode = ItemVirtualizationMode.None;
+
+            Assert.Equal(20, target.Panel.Children.Count);
+            Assert.Equal(new Size(0, 200), scroll.Extent);
+            Assert.Equal(new Size(0, 100), scroll.Viewport);
+        }
+
         private static ItemsPresenter CreateTarget(
             ItemVirtualizationMode mode = ItemVirtualizationMode.Simple,
             Orientation orientation = Orientation.Vertical,