diff --git a/src/Avalonia.Base/Layout/Layoutable.cs b/src/Avalonia.Base/Layout/Layoutable.cs index e526dec0469..170b52491eb 100644 --- a/src/Avalonia.Base/Layout/Layoutable.cs +++ b/src/Avalonia.Base/Layout/Layoutable.cs @@ -543,6 +543,8 @@ protected static void AffectsArrange(params AvaloniaProperty[] properties) /// protected virtual Size MeasureCore(Size availableSize) { + ApplyStyling(); + if (IsVisible) { var margin = Margin; @@ -555,7 +557,6 @@ protected virtual Size MeasureCore(Size availableSize) margin = LayoutHelper.RoundLayoutThickness(margin, scale); } - ApplyStyling(); ApplyTemplate(); var minMax = new MinMax(this); diff --git a/src/Avalonia.Controls/StackPanel.cs b/src/Avalonia.Controls/StackPanel.cs index 007a35c0778..63984592dac 100644 --- a/src/Avalonia.Controls/StackPanel.cs +++ b/src/Avalonia.Controls/StackPanel.cs @@ -261,6 +261,9 @@ protected override Size MeasureOverride(Size availableSize) // Get next child. var child = children[i]; + // Measure the child. + child.Measure(layoutSlotSize); + bool isVisible = child.IsVisible; if (isVisible && !hasVisibleChild) @@ -268,8 +271,6 @@ protected override Size MeasureOverride(Size availableSize) hasVisibleChild = true; } - // Measure the child. - child.Measure(layoutSlotSize); Size childDesiredSize = child.DesiredSize; // Accumulate child size. diff --git a/tests/Avalonia.Base.UnitTests/Layout/MeasureTests.cs b/tests/Avalonia.Base.UnitTests/Layout/MeasureTests.cs index 32c3e89b747..83c634d6ae5 100644 --- a/tests/Avalonia.Base.UnitTests/Layout/MeasureTests.cs +++ b/tests/Avalonia.Base.UnitTests/Layout/MeasureTests.cs @@ -1,10 +1,39 @@ using Avalonia.Controls; +using Avalonia.Styling; +using Avalonia.UnitTests; using Xunit; namespace Avalonia.Base.UnitTests.Layout { public class MeasureTests { + [Fact] + public void Style_Hiding_Control_Should_Be_Applied_Before_Measuring() + { + var child = new Border + { + Width = 100, + Height = 100, + Classes = { "hidden" } + }; + var target = new Decorator + { + Child = child + }; + var root = new TestRoot(target); + + root.Styles.Add(new Style(x => x.OfType().Class("hidden")) + { + Setters = { new Setter(Visual.IsVisibleProperty, false) } + }); + + target.Measure(Size.Infinity); + + Assert.False(child.IsVisible); + Assert.Equal(new Size(0,0), child.DesiredSize); + Assert.Equal(new Size(0,0), target.DesiredSize); + } + [Fact] public void Margin_Should_Be_Included_In_DesiredSize() { diff --git a/tests/Avalonia.Controls.UnitTests/StackPanelTests.cs b/tests/Avalonia.Controls.UnitTests/StackPanelTests.cs index 28ad64bac02..dfb8d38d204 100644 --- a/tests/Avalonia.Controls.UnitTests/StackPanelTests.cs +++ b/tests/Avalonia.Controls.UnitTests/StackPanelTests.cs @@ -1,5 +1,6 @@ using System.Linq; using Avalonia.Layout; +using Avalonia.Styling; using Avalonia.UnitTests; using Xunit; @@ -330,6 +331,39 @@ public void Spacing_Not_Added_For_Invisible_Children(Orientation orientation) Assert.Equal(sizeWithTwoChildren, sizeWithThreeChildren); } + [Theory] + [InlineData(Orientation.Horizontal)] + [InlineData(Orientation.Vertical)] + public void Spacing_Not_Added_For_Children_Hidden_By_Style_Applied_During_Measure(Orientation orientation) + { + var target = new StackPanel + { + Spacing = 40, + Orientation = orientation, + Children = + { + new StackPanel { Width = 10, Height = 10, Classes = { "hidden" } }, + new StackPanel { Width = 10, Height = 10 }, + new StackPanel { Width = 10, Height = 10 }, + } + }; + + var root = new TestRoot(target); + + root.Styles.Add(new Style(x => x.OfType().Class("hidden")) + { + Setters = { new Setter(Visual.IsVisibleProperty, false) } + }); + + target.Measure(Size.Infinity); + + var expected = orientation == Orientation.Horizontal ? + new Size(60, 10) : + new Size(10, 60); + + Assert.Equal(expected, target.DesiredSize); + } + [Theory] [InlineData(Orientation.Horizontal)] [InlineData(Orientation.Vertical)] diff --git a/tests/Avalonia.Controls.UnitTests/WindowTests.cs b/tests/Avalonia.Controls.UnitTests/WindowTests.cs index ebd07d25965..ccc7e0ca0fc 100644 --- a/tests/Avalonia.Controls.UnitTests/WindowTests.cs +++ b/tests/Avalonia.Controls.UnitTests/WindowTests.cs @@ -1642,6 +1642,83 @@ public void WindowDecorationsTheme_Should_Apply_To_Decorations() } } + [Fact] + public void IsVisible_Setter_Should_Affect_Measurements_Inside_WindowDrawnDecorationsContent() + { + using var app = UnitTestApplication.Start(TestServices.StyledWindow); + + var windowImpl = MockWindowingPlatform.CreateWindowMock(); + windowImpl.Setup(x => x.NeedsManagedDecorations).Returns(true); + windowImpl.Setup(x => x.RequestedDrawnDecorations).Returns(PlatformRequestedDrawnDecoration.TitleBar); + + var window = new Window(windowImpl.Object); + + var stackPanel = new StackPanel + { + Width = 32, + Spacing = 2, + Children = + { + new Control { Height = 32 }, + new Control + { + Height = 32, + Classes = { "hidden-by-style" } + }, + } + }; + + var contentControl = new ContentControl + { + Content = new Control + { + Height = 32, + Width = 32, + Classes = { "hidden-by-style" } + } + }; + + var content = new WindowDrawnDecorationsContent + { + Overlay = new ContentControl + { + Content = new Panel + { + Children = { stackPanel, contentControl } + } + } + }; + + var template = new WindowDrawnDecorationsTemplate + { + Content = (IServiceProvider? _) => new TemplateResult(content, new NameScope()) + }; + + var theme = new ControlTheme(typeof(WindowDrawnDecorations)) + { + Setters = + { + new Setter(WindowDrawnDecorations.TemplateProperty, template) + } + }; + + var style = new Style(x => x.Is().Template().OfType().Class("hidden-by-style")) + { + Setters = + { + new Setter(Visual.IsVisibleProperty, false) + } + }; + + window.WindowDecorationsTheme = theme; + window.Styles.Add(style); + window.Show(); + window.Measure(Size.Infinity); + + Assert.Equal(new Size(), contentControl.DesiredSize); + Assert.Equal(new Size(32, 32), stackPanel.DesiredSize); + } + public class TitleBarDecorationsTests : ScopedTestBase { private static Window CreateWindowWithDrawnDecorations(PlatformAllowedWindowActions allowedActions = PlatformAllowedWindowActions.All)