From 240bc4d2ca0986a25c0568cb174407bea1f770ec Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 16 Jan 2017 17:25:12 -0800 Subject: [PATCH] Fix horizontal scroll with virtualized items. Fixes #849 --- src/Avalonia.Controls/IVirtualizingPanel.cs | 5 ++++ .../Presenters/ItemVirtualizer.cs | 13 +++++++-- .../VirtualizingStackPanel.cs | 27 +++++++++++++++++-- ...emsPresenterTests_Virtualization_Simple.cs | 18 +++++++++++++ 4 files changed, 59 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Controls/IVirtualizingPanel.cs b/src/Avalonia.Controls/IVirtualizingPanel.cs index 792dee8ae8..2d8dcb42e3 100644 --- a/src/Avalonia.Controls/IVirtualizingPanel.cs +++ b/src/Avalonia.Controls/IVirtualizingPanel.cs @@ -66,6 +66,11 @@ namespace Avalonia.Controls /// double PixelOffset { get; set; } + /// + /// Gets or sets the current scroll offset in the cross axis. + /// + double CrossAxisOffset { get; set; } + /// /// Invalidates the measure of the control and forces a call to /// on the next measure. diff --git a/src/Avalonia.Controls/Presenters/ItemVirtualizer.cs b/src/Avalonia.Controls/Presenters/ItemVirtualizer.cs index c4edaf5387..fee326dacc 100644 --- a/src/Avalonia.Controls/Presenters/ItemVirtualizer.cs +++ b/src/Avalonia.Controls/Presenters/ItemVirtualizer.cs @@ -206,8 +206,17 @@ namespace Avalonia.Controls.Presenters /// The actual size used. 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; } diff --git a/src/Avalonia.Controls/VirtualizingStackPanel.cs b/src/Avalonia.Controls/VirtualizingStackPanel.cs index 2e5afaf170..834f6d218b 100644 --- a/src/Avalonia.Controls/VirtualizingStackPanel.cs +++ b/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) diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs index e603925e31..2f98cccadf 100644 --- a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs +++ b/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