Browse Source

Added UnitTests ScrollIntoView_Correctly_Scrolls_Right_To_A_Page_Of_[Smaller/Larger]_Items for the horizontal orientation

pull/17135/head
dbriard 2 years ago
parent
commit
9aa7ac23b4
  1. 92
      tests/Avalonia.Controls.UnitTests/VirtualizingStackPanelTests.cs

92
tests/Avalonia.Controls.UnitTests/VirtualizingStackPanelTests.cs

@ -30,6 +30,13 @@ namespace Avalonia.Controls.UnitTests
[!Layoutable.HeightProperty] = new Binding("Height"),
});
private static FuncDataTemplate<ItemWithWidth> CanvasWithWidthTemplate = new((_, _) =>
new Canvas
{
Height = 100,
[!Layoutable.WidthProperty] = new Binding("Width"),
});
[Fact]
public void Creates_Initial_Items()
{
@ -1192,6 +1199,58 @@ namespace Avalonia.Controls.UnitTests
AssertRealizedItems(target, itemsControl, 15, 5);
}
[Fact]
public void ScrollIntoView_Correctly_Scrolls_Right_To_A_Page_Of_Smaller_Items()
{
using var app = App();
// First 10 items have width of 20, next 10 have width of 10.
var items = Enumerable.Range(0, 20).Select(x => new ItemWithWidth(x, ((29 - x) / 10) * 10));
var (target, scroll, itemsControl) = CreateTarget(items: items, itemTemplate: CanvasWithWidthTemplate, orientation: Orientation.Horizontal);
// Scroll the last item into view.
target.ScrollIntoView(19);
// At the time of the scroll, the average item width is 20, so the requested item
// should be placed at 380 (19 * 20) which therefore results in an extent of 390 to
// accommodate the item width of 10. This is obviously not a perfect answer, but
// it's the best we can do without knowing the actual item widths.
var container = Assert.IsType<ContentPresenter>(target.ContainerFromIndex(19));
Assert.Equal(new Rect(380, 0, 10, 100), container.Bounds);
Assert.Equal(new Size(100, 100), scroll.Viewport);
Assert.Equal(new Size(390, 100), scroll.Extent);
Assert.Equal(new Vector(290, 0), scroll.Offset);
// Items 10-19 should be visible.
AssertRealizedItems(target, itemsControl, 10, 10);
}
[Fact]
public void ScrollIntoView_Correctly_Scrolls_Right_To_A_Page_Of_Larger_Items()
{
using var app = App();
// First 10 items have width of 10, next 10 have width of 20.
var items = Enumerable.Range(0, 20).Select(x => new ItemWithWidth(x, ((x / 10) + 1) * 10));
var (target, scroll, itemsControl) = CreateTarget(items: items, itemTemplate: CanvasWithWidthTemplate, orientation: Orientation.Horizontal);
// Scroll the last item into view.
target.ScrollIntoView(19);
// At the time of the scroll, the average item width is 10, so the requested item
// should be placed at 190 (19 * 10) which therefore results in an extent of 210 to
// accommodate the item width of 20. This is obviously not a perfect answer, but
// it's the best we can do without knowing the actual item widths.
var container = Assert.IsType<ContentPresenter>(target.ContainerFromIndex(19));
Assert.Equal(new Rect(190, 0, 20, 100), container.Bounds);
Assert.Equal(new Size(100, 100), scroll.Viewport);
Assert.Equal(new Size(210, 100), scroll.Extent);
Assert.Equal(new Vector(110, 0), scroll.Offset);
// Items 15-19 should be visible.
AssertRealizedItems(target, itemsControl, 15, 5);
}
private static IReadOnlyList<int> GetRealizedIndexes(VirtualizingStackPanel target, ItemsControl itemsControl)
{
return target.GetRealizedElements()
@ -1242,21 +1301,24 @@ namespace Avalonia.Controls.UnitTests
private static (VirtualizingStackPanel, ScrollViewer, ItemsControl) CreateTarget(
IEnumerable<object>? items = null,
Optional<IDataTemplate?> itemTemplate = default,
IEnumerable<Style>? styles = null)
IEnumerable<Style>? styles = null,
Orientation orientation = Orientation.Vertical)
{
return CreateTarget<ItemsControl>(
items: items,
itemTemplate: itemTemplate,
styles: styles);
styles: styles,
orientation: orientation);
}
private static (VirtualizingStackPanel, ScrollViewer, T) CreateTarget<T>(
IEnumerable<object>? items = null,
Optional<IDataTemplate?> itemTemplate = default,
IEnumerable<Style>? styles = null)
IEnumerable<Style>? styles = null,
Orientation orientation = Orientation.Vertical)
where T : ItemsControl, new()
{
var (target, scroll, itemsControl) = CreateUnrootedTarget<T>(items, itemTemplate);
var (target, scroll, itemsControl) = CreateUnrootedTarget<T>(items, itemTemplate, orientation);
var root = CreateRoot(itemsControl, styles: styles);
root.LayoutManager.ExecuteInitialLayoutPass();
@ -1266,10 +1328,11 @@ namespace Avalonia.Controls.UnitTests
private static (VirtualizingStackPanel, ScrollViewer, T) CreateUnrootedTarget<T>(
IEnumerable<object>? items = null,
Optional<IDataTemplate?> itemTemplate = default)
Optional<IDataTemplate?> itemTemplate = default,
Orientation orientation = Orientation.Vertical)
where T : ItemsControl, new()
{
var target = new VirtualizingStackPanel();
var target = new VirtualizingStackPanel { Orientation = orientation };
items ??= new ObservableCollection<string>(Enumerable.Range(0, 100).Select(x => $"Item {x}"));
@ -1285,6 +1348,12 @@ namespace Avalonia.Controls.UnitTests
Template = ScrollViewerTemplate(),
};
if (orientation == Orientation.Horizontal)
{
scroll.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
scroll.VerticalScrollBarVisibility = ScrollBarVisibility.Disabled;
}
var itemsControl = new T
{
ItemsSource = items,
@ -1365,6 +1434,17 @@ namespace Avalonia.Controls.UnitTests
public string Caption { get; set; }
public double Height { get; set; }
}
private class ItemWithWidth
{
public ItemWithWidth(int index, double width = 10)
{
Caption = $"Item {index}";
Width = width;
}
public string Caption { get; set; }
public double Width { get; set; }
}
private class ItemWithIsVisible : NotifyingBase
{

Loading…
Cancel
Save