Browse Source

Don't add virt items when attached to visual tree.

Don't add virtualized items before the virtualizing panel is attached to
the visual tree, as bindings etc won't be set and so measurement will
produce 0,0 causing all items to be materialized.
Steven Kirk 9 years ago
parent
commit
5a72ed8586

+ 2 - 1
src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs

@@ -9,6 +9,7 @@ using Avalonia.Controls.Utils;
 using Avalonia.Input;
 using Avalonia.Layout;
 using Avalonia.Utilities;
+using Avalonia.VisualTree;
 
 namespace Avalonia.Controls.Presenters
 {
@@ -245,7 +246,7 @@ namespace Avalonia.Controls.Presenters
             var generator = Owner.ItemContainerGenerator;
             var panel = VirtualizingPanel;
 
-            if (!panel.IsFull && Items != null)
+            if (!panel.IsFull && Items != null && panel.IsAttachedToVisualTree)
             {
                 var memberSelector = Owner.MemberSelector;
                 var index = NextIndex;

+ 4 - 0
tests/Avalonia.Controls.UnitTests/ListBoxTests.cs

@@ -194,6 +194,10 @@ namespace Avalonia.Controls.UnitTests
 
         private void Prepare(ListBox target)
         {
+            // The ListBox needs to be part of a rooted visual tree.
+            var root = new TestRoot();
+            root.Child = target;
+
             // Apply the template to the ListBox itself.
             target.ApplyTemplate();
 

+ 55 - 1
tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization.cs

@@ -1,6 +1,7 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // 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.Controls.Generators;
@@ -8,6 +9,7 @@ using Avalonia.Controls.Presenters;
 using Avalonia.Controls.Primitives;
 using Avalonia.Controls.Templates;
 using Avalonia.Layout;
+using Avalonia.Rendering;
 using Avalonia.UnitTests;
 using Xunit;
 
@@ -15,6 +17,43 @@ namespace Avalonia.Controls.UnitTests.Presenters
 {
     public class ItemsPresenterTests_Virtualization
     {
+        [Fact]
+        public void Should_Not_Create_Items_Before_Added_To_Visual_Tree()
+        {
+            var items = Enumerable.Range(0, 10).Select(x => $"Item {x}").ToList();
+            var target = new TestItemsPresenter(true)
+            {
+                Items = items,
+                ItemsPanel = VirtualizingPanelTemplate(Orientation.Vertical),
+                ItemTemplate = ItemTemplate(),
+                VirtualizationMode = ItemVirtualizationMode.Simple,
+            };
+
+            var scroller = new ScrollContentPresenter
+            {
+                Content = target,
+            };
+
+            scroller.UpdateChild();
+            target.ApplyTemplate();
+            target.Measure(new Size(100, 100));
+            target.Arrange(new Rect(0, 0, 100, 100));
+
+            Assert.Empty(target.Panel.Children);
+
+            var root = new TestRoot
+            {
+                Child = scroller,
+            };
+
+            target.InvalidateMeasure();
+            target.Panel.InvalidateMeasure();
+            target.Measure(new Size(100, 100));
+            target.Arrange(new Rect(0, 0, 100, 100));
+
+            Assert.Equal(10, target.Panel.Children.Count);
+        }
+
         [Fact]
         public void Should_Return_IsLogicalScrollEnabled_False_When_Has_No_Virtualizing_Panel()
         {
@@ -239,7 +278,7 @@ namespace Avalonia.Controls.UnitTests.Presenters
             ItemsPresenter result;
             var items = Enumerable.Range(0, itemCount).Select(x => $"Item {x}").ToList();
 
-            var scroller = new ScrollContentPresenter
+            var scroller = new TestScroller
             {
                 Content = result = new TestItemsPresenter(useContainers)
                 {
@@ -273,6 +312,21 @@ namespace Avalonia.Controls.UnitTests.Presenters
             });
         }
 
+        private class TestScroller : ScrollContentPresenter, IRenderRoot
+        {
+            public IRenderQueueManager RenderQueueManager { get; }
+
+            public Point PointToClient(Point point)
+            {
+                throw new NotImplementedException();
+            }
+
+            public Point PointToScreen(Point point)
+            {
+                throw new NotImplementedException();
+            }
+        }
+
         private class TestItemsPresenter : ItemsPresenter
         {
             private bool _useContainers;

+ 18 - 1
tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs

@@ -1,6 +1,7 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
+using System;
 using System.Collections;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
@@ -11,6 +12,7 @@ using Avalonia.Controls.Presenters;
 using Avalonia.Controls.Primitives;
 using Avalonia.Controls.Templates;
 using Avalonia.Input;
+using Avalonia.Rendering;
 using Avalonia.UnitTests;
 using Xunit;
 
@@ -730,7 +732,7 @@ namespace Avalonia.Controls.UnitTests.Presenters
                 (IEnumerable)new AvaloniaList<string>(itemsSource) :
                 (IEnumerable)new ObservableCollection<string>(itemsSource);
 
-            var scroller = new ScrollContentPresenter
+            var scroller = new TestScroller
             {
                 Content = result = new TestItemsPresenter(useContainers)
                 {
@@ -764,6 +766,21 @@ namespace Avalonia.Controls.UnitTests.Presenters
             });
         }
 
+        private class TestScroller : ScrollContentPresenter, IRenderRoot
+        {
+            public IRenderQueueManager RenderQueueManager { get; }
+
+            public Point PointToClient(Point point)
+            {
+                throw new NotImplementedException();
+            }
+
+            public Point PointToScreen(Point point)
+            {
+                throw new NotImplementedException();
+            }
+        }
+
         private class TestItemsPresenter : ItemsPresenter
         {
             private bool _useContainers;