Browse Source

Add containers at beginning when scrolled to end.

Steven Kirk 9 years ago
parent
commit
722a329106

+ 6 - 0
src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs

@@ -84,6 +84,12 @@ namespace Avalonia.Controls.Generators
             IMemberSelector selector)
         {
             var container = ContainerFromIndex(oldIndex);
+
+            if (container == null)
+            {
+                throw new IndexOutOfRangeException("Could not recycle container: not materialized.");
+            }
+
             var i = selector != null ? selector.Select(item) : item;
 
             container.SetValue(ContentProperty, i);

+ 34 - 8
src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs

@@ -105,22 +105,48 @@ namespace Avalonia.Controls.Presenters
 
             if (!panel.IsFull && Items != null)
             {
-                var index = NextIndex;
-                var items = Items.Cast<object>().Skip(index);
                 var memberSelector = Owner.MemberSelector;
+                var index = NextIndex;
+                var step = 1;
 
-                foreach (var item in items)
+                while (!panel.IsFull)
                 {
-                    var materialized = generator.Materialize(index++, item, memberSelector);
-                    panel.Children.Add(materialized.ContainerControl);
+                    if (index == ItemCount)
+                    {
+                        if (FirstIndex == 0)
+                        {
+                            break;
+                        }
+                        else
+                        {
+                            index = FirstIndex - 1;
+                            step = -1;
+                        }
+                    }
+
+                    var materialized = generator.Materialize(index, Items.ElementAt(index), memberSelector);
 
-                    if (panel.IsFull)
+                    if (step == 1)
                     {
-                        break;
+                        panel.Children.Add(materialized.ContainerControl);
                     }
+                    else
+                    {
+                        panel.Children.Insert(0, materialized.ContainerControl);
+                    }
+
+                    index += step;
                 }
 
-                NextIndex = index;
+                if (step == 1)
+                {
+                    NextIndex = index;
+                }
+                else
+                {
+                    NextIndex = ItemCount;
+                    FirstIndex = index + 1;
+                }
             }
 
             if (panel.OverflowCount > 0)

+ 23 - 0
tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs

@@ -74,6 +74,29 @@ namespace Avalonia.Controls.UnitTests.Presenters
             Assert.Equal(8, target.Panel.Children.Count);
         }
 
+        [Fact]
+        public void Should_Add_New_Items_At_Top_When_Control_Is_Scrolled_To_Bottom_And_Enlarged()
+        {
+            var target = CreateTarget();
+            var items = (IList<string>)target.Items;
+
+            target.ApplyTemplate();
+            target.Measure(new Size(100, 100));
+            target.Arrange(new Rect(0, 0, 100, 100));
+
+            Assert.Equal(10, target.Panel.Children.Count);
+
+            ((IScrollable)target).Offset = new Vector(0, 10);
+            target.Arrange(new Rect(0, 0, 100, 120));
+
+            Assert.Equal(12, target.Panel.Children.Count);
+
+            for (var i = 0; i < target.Panel.Children.Count; ++i)
+            {
+                Assert.Equal(items[i + 8], target.Panel.Children[i].DataContext);
+            }
+        }
+
         [Fact]
         public void Should_Update_Containers_When_Items_Changes()
         {