Browse Source

Merge pull request #10864 from AvaloniaUI/fixes/10814-dont-layout-invisible-controls

Don't layout invisible controls
pull/10874/head
Max Katz 3 years ago
committed by GitHub
parent
commit
3d6dce88e5
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 24
      src/Avalonia.Base/Layout/LayoutManager.cs
  2. 18
      tests/Avalonia.Base.UnitTests/Layout/LayoutManagerTests.cs
  3. 2
      tests/Avalonia.Controls.UnitTests/MenuItemTests.cs
  4. 1
      tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs
  5. 2
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ControlThemeTests.cs

24
src/Avalonia.Base/Layout/LayoutManager.cs

@ -269,21 +269,25 @@ namespace Avalonia.Layout
}
}
private void Measure(Layoutable control)
private bool Measure(Layoutable control)
{
if (!control.IsVisible || !control.IsAttachedToVisualTree)
return false;
// Controls closest to the visual root need to be arranged first. We don't try to store
// ordered invalidation lists, instead we traverse the tree upwards, measuring the
// controls closest to the root first. This has been shown by benchmarks to be the
// fastest and most memory-efficient algorithm.
if (control.VisualParent is Layoutable parent)
{
Measure(parent);
if (!Measure(parent))
return false;
}
// If the control being measured has IsMeasureValid == true here then its measure was
// handed by an ancestor and can be ignored. The measure may have also caused the
// control to be removed.
if (!control.IsMeasureValid && control.IsAttachedToVisualTree)
if (!control.IsMeasureValid)
{
if (control is ILayoutRoot root)
{
@ -294,16 +298,22 @@ namespace Avalonia.Layout
control.Measure(control.PreviousMeasure.Value);
}
}
return true;
}
private void Arrange(Layoutable control)
private bool Arrange(Layoutable control)
{
if (!control.IsVisible || !control.IsAttachedToVisualTree)
return false;
if (control.VisualParent is Layoutable parent)
{
Arrange(parent);
if (!Arrange(parent))
return false;
}
if (!control.IsArrangeValid && control.IsAttachedToVisualTree)
if (control.IsMeasureValid && !control.IsArrangeValid)
{
if (control is IEmbeddedLayoutRoot embeddedRoot)
control.Arrange(new Rect(embeddedRoot.AllocatedSize));
@ -316,6 +326,8 @@ namespace Avalonia.Layout
control.Arrange(control.PreviousArrange.Value);
}
}
return true;
}
private void QueueLayoutPass()

18
tests/Avalonia.Base.UnitTests/Layout/LayoutManagerTests.cs

@ -41,6 +41,24 @@ namespace Avalonia.Base.UnitTests.Layout
Assert.False(control.Arranged);
}
[Fact]
public void Doesnt_Measure_And_Arrange_InvalidateMeasured_Control_When_Ancestor_Is_Not_Visible()
{
var control = new LayoutTestControl();
var parent = new Decorator { Child = control };
var root = new LayoutTestRoot { Child = parent };
root.LayoutManager.ExecuteInitialLayoutPass();
control.Measured = control.Arranged = false;
parent.IsVisible = false;
control.InvalidateMeasure();
root.LayoutManager.ExecuteLayoutPass();
Assert.False(control.Measured);
Assert.False(control.Arranged);
}
[Fact]
public void Arranges_InvalidateArranged_Control()
{

2
tests/Avalonia.Controls.UnitTests/MenuItemTests.cs

@ -334,6 +334,7 @@ namespace Avalonia.Controls.UnitTests
};
var window = new Window { Content = menu };
window.Show();
window.LayoutManager.ExecuteInitialLayoutPass();
topLevelMenu.IsSubMenuOpen = true;
@ -371,6 +372,7 @@ namespace Avalonia.Controls.UnitTests
};
var window = new Window { Content = menu };
window.Show();
window.LayoutManager.ExecuteInitialLayoutPass();
var panel = Assert.IsType<StackPanel>(menu.Presenter.Panel);

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

@ -1116,6 +1116,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
private static Window PreparedWindow(object content = null)
{
var w = new Window { Content = content };
w.Show();
w.ApplyStyling();
w.ApplyTemplate();
return w;

2
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ControlThemeTests.cs

@ -27,6 +27,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var button = Assert.IsType<TestTemplatedControl>(window.Content);
window.Show();
window.LayoutManager.ExecuteInitialLayoutPass();
Assert.NotNull(button.Template);
@ -63,6 +64,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var button = Assert.IsType<TestTemplatedControl>(window.Content);
window.Show();
window.LayoutManager.ExecuteInitialLayoutPass();
Assert.NotNull(button.Template);

Loading…
Cancel
Save