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