Browse Source

Fix LayoutUpdated and EffectiveViewportChanged double registration (#17196)

* Add failing test for LayoutUpdated and EffectiveViewportChanged

* Fix LayoutUpdated and EffectiveViewportChanged registration
pull/17211/head
Julien Lebosquain 1 year ago
committed by GitHub
parent
commit
51dbf954ef
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 16
      src/Avalonia.Base/Layout/Layoutable.cs
  2. 24
      tests/Avalonia.Base.UnitTests/Layout/LayoutableTests.cs
  3. 22
      tests/Avalonia.Base.UnitTests/Layout/LayoutableTests_EffectiveViewportChanged.cs

16
src/Avalonia.Base/Layout/Layoutable.cs

@ -135,6 +135,7 @@ namespace Avalonia.Layout
private Rect? _previousArrange;
private EventHandler<EffectiveViewportChangedEventArgs>? _effectiveViewportChanged;
private EventHandler? _layoutUpdated;
private bool _isAttachingToVisualTree;
/// <summary>
/// Initializes static members of the <see cref="Layoutable"/> class.
@ -164,7 +165,7 @@ namespace Avalonia.Layout
{
add
{
if (_effectiveViewportChanged is null && VisualRoot is ILayoutRoot r)
if (_effectiveViewportChanged is null && VisualRoot is ILayoutRoot r && !_isAttachingToVisualTree)
{
r.LayoutManager.RegisterEffectiveViewportListener(this);
}
@ -190,7 +191,7 @@ namespace Avalonia.Layout
{
add
{
if (_layoutUpdated is null && VisualRoot is ILayoutRoot r)
if (_layoutUpdated is null && VisualRoot is ILayoutRoot r && !_isAttachingToVisualTree)
{
r.LayoutManager.LayoutUpdated += LayoutManagedLayoutUpdated;
}
@ -735,9 +736,18 @@ namespace Avalonia.Layout
InvalidateMeasure();
}
/// <inheritdoc />
protected override void OnAttachedToVisualTreeCore(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTreeCore(e);
_isAttachingToVisualTree = true;
try
{
base.OnAttachedToVisualTreeCore(e);
}
finally
{
_isAttachingToVisualTree = false;
}
if (e.Root is ILayoutRoot r)
{

24
tests/Avalonia.Base.UnitTests/Layout/LayoutableTests.cs

@ -291,6 +291,30 @@ namespace Avalonia.Base.UnitTests.Layout
Times.Once);
}
[Fact]
public void LayoutManager_LayoutUpdated_Should_Not_Be_Subscribed_Twice_In_AttachedToVisualTree()
{
Border border1;
var layoutManager = new Mock<ILayoutManager>();
layoutManager.SetupAdd(m => m.LayoutUpdated += (_, _) => { });
_ = new TestRoot
{
Child = border1 = new Border(),
LayoutManager = layoutManager.Object,
};
var border2 = new Border();
border2.AttachedToVisualTree += (_, _) => border2.LayoutUpdated += (_, _) => { };
layoutManager.Invocations.Clear();
border1.Child = border2;
layoutManager.VerifyAdd(
x => x.LayoutUpdated += It.IsAny<EventHandler>(),
Times.Once);
}
[Fact]
public void Making_Control_Invisible_Should_Invalidate_Parent_Measure()
{

22
tests/Avalonia.Base.UnitTests/Layout/LayoutableTests_EffectiveViewportChanged.cs

@ -57,6 +57,28 @@ namespace Avalonia.Base.UnitTests.Layout
});
}
[Fact]
public async Task EffectiveViewportChanged_Should_Not_Be_Raised_Twice_If_Subcribed_In_AttachedToVisualTree()
{
await RunOnUIThread.Execute(async () =>
{
var root = CreateRoot();
var target = new Canvas();
var raised = 0;
target.AttachedToVisualTree += (_, _) =>
{
target.EffectiveViewportChanged += (_, _) => ++raised;
};
root.Child = target;
await ExecuteInitialLayoutPass(root);
Assert.Equal(1, raised);
});
}
[Fact]
public async Task Parent_Affects_EffectiveViewport()
{

Loading…
Cancel
Save