Browse Source

Fix ScrollContentPresenter incorrectly handling BringIntoView without changing its offset (#14900)

* Added failing test for nested ScrollContentPresenters

* Fix nested ScrollContentPresenter w/ content larger than viewport
pull/14913/head
Julien Lebosquain 2 years ago
committed by GitHub
parent
commit
86bfc26ace
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 12
      src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs
  2. 2
      src/Avalonia.Controls/VirtualizingStackPanel.cs
  3. 43
      tests/Avalonia.Controls.UnitTests/Presenters/ScrollContentPresenterTests.cs

12
src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs

@ -259,38 +259,34 @@ namespace Avalonia.Controls.Presenters
var rect = targetRect.TransformToAABB(transform.Value);
var offset = Offset;
var result = false;
if (rect.Bottom > offset.Y + Viewport.Height)
{
offset = offset.WithY((rect.Bottom - Viewport.Height) + Child.Margin.Top);
result = true;
}
if (rect.Y < offset.Y)
{
offset = offset.WithY(rect.Y);
result = true;
}
if (rect.Right > offset.X + Viewport.Width)
{
offset = offset.WithX((rect.Right - Viewport.Width) + Child.Margin.Left);
result = true;
}
if (rect.X < offset.X)
{
offset = offset.WithX(rect.X);
result = true;
}
if (result)
if (Offset.NearlyEquals(offset))
{
SetCurrentValue(OffsetProperty, offset);
return false;
}
return result;
SetCurrentValue(OffsetProperty, offset);
return true;
}
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)

2
src/Avalonia.Controls/VirtualizingStackPanel.cs

@ -453,8 +453,6 @@ namespace Avalonia.Controls
{
Debug.Assert(_realizedElements is not null);
// If the control has not yet been laid out then the effective viewport won't have been set.
// Try to work it out from an ancestor control.
var viewport = _viewport;
// Get the viewport in the orientation direction.

43
tests/Avalonia.Controls.UnitTests/Presenters/ScrollContentPresenterTests.cs

@ -2,7 +2,6 @@ using System;
using System.Collections.Generic;
using System.Reactive.Linq;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives;
using Avalonia.Layout;
using Avalonia.UnitTests;
using Xunit;
@ -366,7 +365,7 @@ namespace Avalonia.Controls.UnitTests.Presenters
target.UpdateChild();
target.Measure(Size.Infinity);
target.Arrange(new Rect(0, 0, 100, 100));
target.BringDescendantIntoView(target.Child, new Rect(200, 200, 0, 0));
target.BringDescendantIntoView(target.Child!, new Rect(200, 200, 0, 0));
Assert.Equal(new Vector(100, 100), target.Offset);
}
@ -400,6 +399,46 @@ namespace Avalonia.Controls.UnitTests.Presenters
Assert.Equal(new Vector(150, 150), target.Offset);
}
[Fact]
public void Nested_Presenters_Should_Scroll_Outer_When_Content_Exceeds_Viewport()
{
ScrollContentPresenter innerPresenter;
Border border;
var outerPresenter = new ScrollContentPresenter
{
CanHorizontallyScroll = true,
CanVerticallyScroll = true,
Width = 100,
Height = 100,
Content = innerPresenter = new ScrollContentPresenter
{
CanHorizontallyScroll = true,
CanVerticallyScroll = true,
Width = 100,
Height = 200,
Content = border = new Border
{
Width = 200, // larger than viewport
Height = 25,
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top,
Margin = new Thickness(0, 120, 0, 0)
}
}
};
innerPresenter.UpdateChild();
outerPresenter.UpdateChild();
outerPresenter.Measure(new Size(100, 100));
outerPresenter.Arrange(new Rect(0, 0, 100, 100));
border.BringIntoView();
Assert.Equal(new Vector(0, 45), outerPresenter.Offset);
Assert.Equal(new Vector(0, 0), innerPresenter.Offset);
}
private class TestControl : Control
{
public Size AvailableSize { get; private set; }

Loading…
Cancel
Save