Browse Source

Fix PopupRoot.ConfigurePosition being called unnecessary (#17322)

pull/17326/head
Julien Lebosquain 2 years ago
committed by GitHub
parent
commit
fe0b91d541
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 49
      src/Avalonia.Controls/Primitives/Popup.cs
  2. 4
      tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs

49
src/Avalonia.Controls/Primitives/Popup.cs

@ -1,5 +1,6 @@
using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Reactive;
using Avalonia.Automation.Peers;
using Avalonia.Controls.Diagnostics;
@ -152,9 +153,7 @@ namespace Avalonia.Controls.Primitives
{
IsHitTestVisibleProperty.OverrideDefaultValue<Popup>(false);
ChildProperty.Changed.AddClassHandler<Popup>((x, e) => x.ChildChanged(e));
IsOpenProperty.Changed.AddClassHandler<Popup>((x, e) => x.IsOpenChanged((AvaloniaPropertyChangedEventArgs<bool>)e));
VerticalOffsetProperty.Changed.AddClassHandler<Popup>((x, _) => x.HandlePositionChange());
HorizontalOffsetProperty.Changed.AddClassHandler<Popup>((x, _) => x.HandlePositionChange());
IsOpenProperty.Changed.AddClassHandler<Popup>((x, e) => x.IsOpenChanged((AvaloniaPropertyChangedEventArgs<bool>)e));
}
/// <summary>
@ -720,18 +719,7 @@ namespace Avalonia.Controls.Primitives
{
if (_openState != null)
{
var placementTarget = PlacementTarget ?? this.FindLogicalAncestorOfType<Control>();
if (placementTarget == null)
return;
_openState.PopupHost.ConfigurePosition(new PopupPositionRequest(
placementTarget,
Placement,
new Point(HorizontalOffset, VerticalOffset),
PlacementAnchor,
PlacementGravity,
PlacementConstraintAdjustment,
PlacementRect,
CustomPopupPlacementCallback));
UpdateHostPosition(_openState.PopupHost, _openState.PlacementTarget);
}
}
@ -977,7 +965,20 @@ namespace Avalonia.Controls.Primitives
private void WindowPositionChanged(PixelPoint pp) => HandlePositionChange();
private void PlacementTargetLayoutUpdated(object? src, EventArgs e) => HandlePositionChange();
private void PlacementTargetLayoutUpdated(object? src, EventArgs e)
{
if (_openState is null)
return;
// A LayoutUpdated event is raised for the whole visual tree:
// the bounds of the PlacementTarget might not have effectively changed.
var newBounds = _openState.PlacementTarget.Bounds;
if (newBounds == _openState.LastPlacementTargetBounds)
return;
_openState.LastPlacementTargetBounds = newBounds;
UpdateHostPosition(_openState.PopupHost, _openState.PlacementTarget);
}
private void ParentPopupPositionChanged(object? src, PixelPointEventArgs e) => HandlePositionChange();
@ -1006,6 +1007,7 @@ namespace Avalonia.Controls.Primitives
{
private readonly IDisposable _cleanup;
private IDisposable? _presenterCleanup;
private Control _placementTarget;
public PopupOpenState(Control placementTarget, TopLevel topLevel, IPopupHost popupHost, IDisposable cleanup)
{
@ -1016,7 +1018,20 @@ namespace Avalonia.Controls.Primitives
}
public TopLevel TopLevel { get; }
public Control PlacementTarget { get; set; }
public Control PlacementTarget
{
get => _placementTarget;
[MemberNotNull(nameof(_placementTarget))]
set
{
_placementTarget = value;
LastPlacementTargetBounds = value.Bounds;
}
}
public Rect LastPlacementTargetBounds { get; set; }
public IPopupHost PopupHost { get; }
public void SetPresenterSubscription(IDisposable? presenterCleanup)

4
tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs

@ -1244,9 +1244,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
popup.Open();
root.LayoutManager.ExecuteLayoutPass();
// Ideally, callback should be executed only once for this test.
// But currently PlacementTargetLayoutUpdated triggers second update either way.
Assert.Equal(2, callbackExecuted);
Assert.Equal(1, callbackExecuted);
}
}

Loading…
Cancel
Save