|
@@ -1192,6 +1192,112 @@ namespace Avalonia.Controls.UnitTests
|
|
|
AssertRealizedItems(target, itemsControl, 15, 5);
|
|
|
}
|
|
|
|
|
|
+ [Fact]
|
|
|
+ public void Extent_And_Offset_Should_Be_Updated_When_Containers_Resize()
|
|
|
+ {
|
|
|
+ using var app = App();
|
|
|
+
|
|
|
+ // All containers start off with a height of 50 (2 containers fit in viewport).
|
|
|
+ var items = Enumerable.Range(0, 20).Select(x => new ItemWithHeight(x, 50)).ToList();
|
|
|
+ var (target, scroll, itemsControl) = CreateTarget(items: items, itemTemplate: CanvasWithHeightTemplate);
|
|
|
+
|
|
|
+ // Scroll to the 5th item (containers 4 and 5 should be visible).
|
|
|
+ target.ScrollIntoView(5);
|
|
|
+ Assert.Equal(4, target.FirstRealizedIndex);
|
|
|
+ Assert.Equal(5, target.LastRealizedIndex);
|
|
|
+
|
|
|
+ // The extent should be 500 (10 * 50) and the offset should be 200 (4 * 50).
|
|
|
+ var container = Assert.IsType<ContentPresenter>(target.ContainerFromIndex(5));
|
|
|
+ Assert.Equal(new Rect(0, 250, 100, 50), container.Bounds);
|
|
|
+ Assert.Equal(new Size(100, 100), scroll.Viewport);
|
|
|
+ Assert.Equal(new Size(100, 1000), scroll.Extent);
|
|
|
+ Assert.Equal(new Vector(0, 200), scroll.Offset);
|
|
|
+
|
|
|
+ // Update the height of all items to 25 and run a layout pass.
|
|
|
+ foreach (var item in items)
|
|
|
+ item.Height = 25;
|
|
|
+ target.UpdateLayout();
|
|
|
+
|
|
|
+ // The extent should be updated to reflect the new heights. The offset should be
|
|
|
+ // unchanged but the first realized index should be updated to 8 (200 / 25).
|
|
|
+ Assert.Equal(new Size(100, 100), scroll.Viewport);
|
|
|
+ Assert.Equal(new Size(100, 500), scroll.Extent);
|
|
|
+ Assert.Equal(new Vector(0, 200), scroll.Offset);
|
|
|
+ Assert.Equal(8, target.FirstRealizedIndex);
|
|
|
+ Assert.Equal(11, target.LastRealizedIndex);
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void Focused_Container_Is_Positioned_Correctly_when_Container_Size_Change_Causes_It_To_Be_Moved_Out_Of_Visible_Viewport()
|
|
|
+ {
|
|
|
+ using var app = App();
|
|
|
+
|
|
|
+ // All containers start off with a height of 50 (2 containers fit in viewport).
|
|
|
+ var items = Enumerable.Range(0, 20).Select(x => new ItemWithHeight(x, 50)).ToList();
|
|
|
+ var (target, scroll, itemsControl) = CreateTarget(items: items, itemTemplate: CanvasWithHeightTemplate);
|
|
|
+
|
|
|
+ // Scroll to the 5th item (containers 4 and 5 should be visible).
|
|
|
+ target.ScrollIntoView(5);
|
|
|
+ Assert.Equal(4, target.FirstRealizedIndex);
|
|
|
+ Assert.Equal(5, target.LastRealizedIndex);
|
|
|
+
|
|
|
+ // Focus the 5th item.
|
|
|
+ var container = Assert.IsType<ContentPresenter>(target.ContainerFromIndex(5));
|
|
|
+ container.Focusable = true;
|
|
|
+ container.Focus();
|
|
|
+
|
|
|
+ // Update the height of all items to 25 and run a layout pass.
|
|
|
+ foreach (var item in items)
|
|
|
+ item.Height = 25;
|
|
|
+ target.UpdateLayout();
|
|
|
+
|
|
|
+ // The focused container should now be outside the realized range.
|
|
|
+ Assert.Equal(8, target.FirstRealizedIndex);
|
|
|
+ Assert.Equal(11, target.LastRealizedIndex);
|
|
|
+
|
|
|
+ // The container should still exist and be positioned outside the visible viewport.
|
|
|
+ container = Assert.IsType<ContentPresenter>(target.ContainerFromIndex(5));
|
|
|
+ Assert.Equal(new Rect(0, 125, 100, 25), container.Bounds);
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void Focused_Container_Is_Positioned_Correctly_when_Container_Size_Change_Causes_It_To_Be_Moved_Into_Visible_Viewport()
|
|
|
+ {
|
|
|
+ using var app = App();
|
|
|
+
|
|
|
+ // All containers start off with a height of 25 (4 containers fit in viewport).
|
|
|
+ var items = Enumerable.Range(0, 20).Select(x => new ItemWithHeight(x, 25)).ToList();
|
|
|
+ var (target, scroll, itemsControl) = CreateTarget(items: items, itemTemplate: CanvasWithHeightTemplate);
|
|
|
+
|
|
|
+ // Scroll to the 5th item (containers 4-7 should be visible).
|
|
|
+ target.ScrollIntoView(7);
|
|
|
+ Assert.Equal(4, target.FirstRealizedIndex);
|
|
|
+ Assert.Equal(7, target.LastRealizedIndex);
|
|
|
+
|
|
|
+ // Focus the 7th item.
|
|
|
+ var container = Assert.IsType<ContentPresenter>(target.ContainerFromIndex(7));
|
|
|
+ container.Focusable = true;
|
|
|
+ container.Focus();
|
|
|
+
|
|
|
+ // Scroll up to the 3rd item (containers 3-6 should still be visible).
|
|
|
+ target.ScrollIntoView(3);
|
|
|
+ Assert.Equal(3, target.FirstRealizedIndex);
|
|
|
+ Assert.Equal(6, target.LastRealizedIndex);
|
|
|
+
|
|
|
+ // Update the height of all items to 20 and run a layout pass.
|
|
|
+ foreach (var item in items)
|
|
|
+ item.Height = 20;
|
|
|
+ target.UpdateLayout();
|
|
|
+
|
|
|
+ // The focused container should now be inside the realized range.
|
|
|
+ Assert.Equal(3, target.FirstRealizedIndex);
|
|
|
+ Assert.Equal(7, target.LastRealizedIndex);
|
|
|
+
|
|
|
+ // The container should be positioned correctly.
|
|
|
+ container = Assert.IsType<ContentPresenter>(target.ContainerFromIndex(7));
|
|
|
+ Assert.Equal(new Rect(0, 140, 100, 20), container.Bounds);
|
|
|
+ }
|
|
|
+
|
|
|
private static IReadOnlyList<int> GetRealizedIndexes(VirtualizingStackPanel target, ItemsControl itemsControl)
|
|
|
{
|
|
|
return target.GetRealizedElements()
|
|
@@ -1354,8 +1460,10 @@ namespace Avalonia.Controls.UnitTests
|
|
|
|
|
|
private static IDisposable App() => UnitTestApplication.Start(TestServices.RealFocus);
|
|
|
|
|
|
- private class ItemWithHeight
|
|
|
+ private class ItemWithHeight : NotifyingBase
|
|
|
{
|
|
|
+ private double _height;
|
|
|
+
|
|
|
public ItemWithHeight(int index, double height = 10)
|
|
|
{
|
|
|
Caption = $"Item {index}";
|
|
@@ -1363,7 +1471,12 @@ namespace Avalonia.Controls.UnitTests
|
|
|
}
|
|
|
|
|
|
public string Caption { get; set; }
|
|
|
- public double Height { get; set; }
|
|
|
+
|
|
|
+ public double Height
|
|
|
+ {
|
|
|
+ get => _height;
|
|
|
+ set => SetField(ref _height, value);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
private class ItemWithIsVisible : NotifyingBase
|