Browse Source

Fix horizontal scroll with virtualized items.

Fixes #849
Steven Kirk 9 years ago
parent
commit
240bc4d2ca

+ 5 - 0
src/Avalonia.Controls/IVirtualizingPanel.cs

@@ -66,6 +66,11 @@ namespace Avalonia.Controls
         /// </summary>
         double PixelOffset { get; set; }
 
+        /// <summary>
+        /// Gets or sets the current scroll offset in the cross axis.
+        /// </summary>
+        double CrossAxisOffset { get; set; }
+
         /// <summary>
         /// Invalidates the measure of the control and forces a call to 
         /// <see cref="IVirtualizingController.UpdateControls"/> on the next measure.

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

@@ -206,8 +206,17 @@ namespace Avalonia.Controls.Presenters
         /// <returns>The actual size used.</returns>
         public virtual Size ArrangeOverride(Size finalSize)
         {
-            var origin = Vertical ? new Point(-_crossAxisOffset, 0) : new Point(0, _crossAxisOffset);
-            Owner.Panel.Arrange(new Rect(origin, finalSize));
+            if (VirtualizingPanel != null)
+            {
+                VirtualizingPanel.CrossAxisOffset = _crossAxisOffset;
+                Owner.Panel.Arrange(new Rect(finalSize));
+            }
+            else
+            {
+                var origin = Vertical ? new Point(-_crossAxisOffset, 0) : new Point(0, _crossAxisOffset);
+                Owner.Panel.Arrange(new Rect(origin, finalSize));
+            }
+
             return finalSize;
         }
 

+ 25 - 2
src/Avalonia.Controls/VirtualizingStackPanel.cs

@@ -19,6 +19,7 @@ namespace Avalonia.Controls
         private double _averageItemSize;
         private int _averageCount;
         private double _pixelOffset;
+        private double _crossAxisOffset;
         private bool _forceRemeasure;
 
         bool IVirtualizingPanel.IsFull
@@ -60,6 +61,20 @@ namespace Avalonia.Controls
             }
         }
 
+        double IVirtualizingPanel.CrossAxisOffset
+        {
+            get { return _crossAxisOffset; }
+
+            set
+            {
+                if (_crossAxisOffset != value)
+                {
+                    _crossAxisOffset = value;
+                    InvalidateArrange();
+                }
+            }
+        }
+
         private IVirtualizingController Controller => ((IVirtualizingPanel)this).Controller;
 
         void IVirtualizingPanel.ForceInvalidateMeasure()
@@ -140,7 +155,11 @@ namespace Avalonia.Controls
         {
             if (orientation == Orientation.Vertical)
             {
-                rect = new Rect(rect.X, rect.Y - _pixelOffset, rect.Width, rect.Height);
+                rect = new Rect(
+                    rect.X - _crossAxisOffset,
+                    rect.Y - _pixelOffset,
+                    rect.Width,
+                    rect.Height);
                 child.Arrange(rect);
 
                 if (rect.Y >= _availableSpace.Height)
@@ -157,7 +176,11 @@ namespace Avalonia.Controls
             }
             else
             {
-                rect = new Rect(rect.X - _pixelOffset, rect.Y, rect.Width, rect.Height);
+                rect = new Rect(
+                    rect.X - _pixelOffset,
+                    rect.Y - _crossAxisOffset,
+                    rect.Width,
+                    rect.Height);
                 child.Arrange(rect);
 
                 if (rect.X >= _availableSpace.Width)

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

@@ -786,6 +786,24 @@ namespace Avalonia.Controls.UnitTests.Presenters
                 Assert.Equal(new Size(10, 20), ((ILogicalScrollable)target).Extent);
                 Assert.Equal(new Size(5, 10), ((ILogicalScrollable)target).Viewport);
             }
+
+            [Fact]
+            public void Horizontal_Scroll_Should_Update_Item_Position()
+            {
+                var target = CreateTarget();
+
+                target.ApplyTemplate();
+
+                target.Measure(new Size(5, 100));
+                target.Arrange(new Rect(0, 0, 5, 100));
+
+                ((ILogicalScrollable)target).Offset = new Vector(5, 0);
+
+                target.Measure(new Size(5, 100));
+                target.Arrange(new Rect(0, 0, 5, 100));
+
+                Assert.Equal(new Rect(-5, 0, 10, 10), target.Panel.Children[0].Bounds);
+            }
         }
 
         public class Horizontal