Browse Source

Don't create virtualizer before panel.

Otherwise, an `ItemVirtualizerNone` is created which can materialize all items, even if `ItemVirtualizationMode.Simple` is set.

Hopefully fixes #1707.
Steven Kirk 7 years ago
parent
commit
27589e87a8

+ 5 - 0
src/Avalonia.Controls/Presenters/ItemVirtualizer.cs

@@ -161,6 +161,11 @@ namespace Avalonia.Controls.Presenters
         /// <returns>An <see cref="ItemVirtualizer"/>.</returns>
         public static ItemVirtualizer Create(ItemsPresenter owner)
         {
+            if (owner.Panel == null)
+            {
+                return null;
+            }
+
             var virtualizingPanel = owner.Panel as IVirtualizingPanel;
             var scrollable = (ILogicalScrollable)owner;
             ItemVirtualizer result = null;

+ 22 - 14
src/Avalonia.Controls/Presenters/ItemsPresenter.cs

@@ -22,7 +22,6 @@ namespace Avalonia.Controls.Presenters
                 nameof(VirtualizationMode),
                 defaultValue: ItemVirtualizationMode.None);
 
-        private ItemVirtualizer _virtualizer;
         private bool _canHorizontallyScroll;
         private bool _canVerticallyScroll;
 
@@ -76,21 +75,27 @@ namespace Avalonia.Controls.Presenters
         /// <inheritdoc/>
         bool ILogicalScrollable.IsLogicalScrollEnabled
         {
-            get { return _virtualizer?.IsLogicalScrollEnabled ?? false; }
+            get { return Virtualizer?.IsLogicalScrollEnabled ?? false; }
         }
 
         /// <inheritdoc/>
-        Size IScrollable.Extent => _virtualizer.Extent;
+        Size IScrollable.Extent => Virtualizer?.Extent ?? Size.Empty;
 
         /// <inheritdoc/>
         Vector IScrollable.Offset
         {
-            get { return _virtualizer.Offset; }
-            set { _virtualizer.Offset = CoerceOffset(value); }
+            get { return Virtualizer?.Offset ?? new Vector(); }
+            set
+            {
+                if (Virtualizer != null)
+                {
+                    Virtualizer.Offset = CoerceOffset(value);
+                }
+            }
         }
 
         /// <inheritdoc/>
-        Size IScrollable.Viewport => _virtualizer.Viewport;
+        Size IScrollable.Viewport => Virtualizer?.Viewport ?? Bounds.Size;
 
         /// <inheritdoc/>
         Action ILogicalScrollable.InvalidateScroll { get; set; }
@@ -101,6 +106,8 @@ namespace Avalonia.Controls.Presenters
         /// <inheritdoc/>
         Size ILogicalScrollable.PageScrollSize => new Size(0, 1);
 
+        internal ItemVirtualizer Virtualizer { get; private set; }
+
         /// <inheritdoc/>
         bool ILogicalScrollable.BringIntoView(IControl target, Rect targetRect)
         {
@@ -110,29 +117,30 @@ namespace Avalonia.Controls.Presenters
         /// <inheritdoc/>
         IControl ILogicalScrollable.GetControlInDirection(NavigationDirection direction, IControl from)
         {
-            return _virtualizer?.GetControlInDirection(direction, from);
+            return Virtualizer?.GetControlInDirection(direction, from);
         }
 
         public override void ScrollIntoView(object item)
         {
-            _virtualizer?.ScrollIntoView(item);
+            Virtualizer?.ScrollIntoView(item);
         }
 
         /// <inheritdoc/>
         protected override Size MeasureOverride(Size availableSize)
         {
-            return _virtualizer?.MeasureOverride(availableSize) ?? Size.Empty;
+            return Virtualizer?.MeasureOverride(availableSize) ?? Size.Empty;
         }
 
         protected override Size ArrangeOverride(Size finalSize)
         {
-            return _virtualizer?.ArrangeOverride(finalSize) ?? Size.Empty;
+            return Virtualizer?.ArrangeOverride(finalSize) ?? Size.Empty;
         }
 
         /// <inheritdoc/>
         protected override void PanelCreated(IPanel panel)
         {
-            _virtualizer = ItemVirtualizer.Create(this);
+            Virtualizer?.Dispose();
+            Virtualizer = ItemVirtualizer.Create(this);
             ((ILogicalScrollable)this).InvalidateScroll?.Invoke();
 
             if (!Panel.IsSet(KeyboardNavigation.DirectionalNavigationProperty))
@@ -149,7 +157,7 @@ namespace Avalonia.Controls.Presenters
 
         protected override void ItemsChanged(NotifyCollectionChangedEventArgs e)
         {
-            _virtualizer?.ItemsChanged(Items, e);
+            Virtualizer?.ItemsChanged(Items, e);
         }
 
         private Vector CoerceOffset(Vector value)
@@ -162,8 +170,8 @@ namespace Avalonia.Controls.Presenters
 
         private void VirtualizationModeChanged(AvaloniaPropertyChangedEventArgs e)
         {
-            _virtualizer?.Dispose();
-            _virtualizer = ItemVirtualizer.Create(this);
+            Virtualizer?.Dispose();
+            Virtualizer = ItemVirtualizer.Create(this);
             ((ILogicalScrollable)this).InvalidateScroll?.Invoke();
         }
     }

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

@@ -194,6 +194,15 @@ namespace Avalonia.Controls.UnitTests.Presenters
             }
         }
 
+        [Fact]
+        public void Should_Not_Create_Virtualizer_Before_Panel()
+        {
+            var target = CreateTarget();
+
+            Assert.Null(target.Panel);
+            Assert.Null(target.Virtualizer);
+        }
+
         [Fact]
         public void Changing_VirtualizationMode_None_To_Simple_Should_Update_Control()
         {