From 5a72ed8586678935a2b010cde7ed35686b497082 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 5 Jul 2016 20:51:09 +0200 Subject: [PATCH] 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. --- .../Presenters/ItemVirtualizerSimple.cs | 3 +- .../ListBoxTests.cs | 4 ++ .../ItemsPresenterTests_Virtualization.cs | 56 ++++++++++++++++++- ...emsPresenterTests_Virtualization_Simple.cs | 19 ++++++- 4 files changed, 79 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs b/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs index 27a29a1e04..a54e502033 100644 --- a/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs +++ b/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; diff --git a/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs b/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs index db2bb0f886..7e1347daf5 100644 --- a/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs +++ b/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(); diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization.cs index 26657a0fbb..2f6361a867 100644 --- a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization.cs +++ b/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; diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs index aa02ecb666..34b074d185 100644 --- a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs +++ b/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(itemsSource) : (IEnumerable)new ObservableCollection(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;