Browse Source

Double BringIntoView in VirtualizingStackPanel (#14419)

This fixes a case when elements have different widths and the BringIntoView wants to scroll horizontally due to custom TargetRect

Co-authored-by: Max Katz <maxkatz6@outlook.com>
release/11.0.8
Bartosz Korczyński 2 years ago
committed by Max Katz
parent
commit
873bb90ef9
  1. 6
      src/Avalonia.Controls/VirtualizingStackPanel.cs
  2. 38
      tests/Avalonia.Controls.UnitTests/VirtualizingStackPanelTests.cs

6
src/Avalonia.Controls/VirtualizingStackPanel.cs

@ -430,6 +430,12 @@ namespace Avalonia.Controls
root.LayoutManager.ExecuteLayoutPass();
}
// During the previous BringIntoView, the scroll width extent might have been out of date if
// elements have different widths. Because of that, the ScrollViewer might not scroll to the correct offset.
// After the previous BringIntoView, Y offset should be correct and an extra layout pass has been executed,
// hence the width extent should be correct now, and we can try to scroll again.
scrollToElement.BringIntoView();
_scrollToElement = null;
_scrollToIndex = -1;
return scrollToElement;

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

@ -1116,6 +1116,44 @@ namespace Avalonia.Controls.UnitTests
Assert.True(container.IsVisible);
}
[Fact]
public void ScrollIntoView_With_TargetRect_Outside_Viewport_Should_Scroll_To_Item()
{
using var app = App();
var items = Enumerable.Range(0, 101).Select(x => new ItemWithHeight(x, x * 100 + 1));
var itemTemplate = new FuncDataTemplate<ItemWithHeight>((x, _) =>
new Border
{
Height = 10,
[!Layoutable.WidthProperty] = new Binding("Height"),
});
var (target, scroll, itemsControl) = CreateTarget(
items: items,
itemTemplate: itemTemplate,
styles: new[]
{
new Style(x => x.OfType<ScrollViewer>())
{
Setters =
{
new Setter(ScrollViewer.HorizontalScrollBarVisibilityProperty, ScrollBarVisibility.Visible),
}
}
});
itemsControl.ContainerPrepared += (_, ev) =>
{
ev.Container.AddHandler(Control.RequestBringIntoViewEvent, (_, e) =>
{
var dataContext = e.TargetObject.DataContext as ItemWithHeight;
e.TargetRect = new Rect(dataContext.Height - 50, 0, 50, 10);
});
};
target.ScrollIntoView(100);
Assert.Equal(9901, scroll.Offset.X);
}
private static IReadOnlyList<int> GetRealizedIndexes(VirtualizingStackPanel target, ItemsControl itemsControl)
{
return target.GetRealizedElements()

Loading…
Cancel
Save