From 055e123b5cb48e79260fb1bf5c36091214266ff1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BE=8A=E6=92=85=E6=92=85?= <31302548+Fachep@users.noreply.github.com> Date: Wed, 19 Aug 2026 14:43:27 +0000 Subject: [PATCH] Call ApplyStyling unconditionally in MeasureCore (#21572) * Add unit test for styling affecting measurements in WindowDrawnDecorationsContent * Refactor layout measurement to apply styling before visibility checks * Add core measure test * Add StackPanel test * Call ApplyStyling unconditionally in MeasureCore --------- Co-authored-by: Julien Lebosquain --- src/Avalonia.Base/Layout/Layoutable.cs | 3 +- src/Avalonia.Controls/StackPanel.cs | 5 +- .../Layout/MeasureTests.cs | 29 +++++++ .../StackPanelTests.cs | 34 ++++++++ .../WindowTests.cs | 77 +++++++++++++++++++ 5 files changed, 145 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Base/Layout/Layoutable.cs b/src/Avalonia.Base/Layout/Layoutable.cs index e526dec046..170b52491e 100644 --- a/src/Avalonia.Base/Layout/Layoutable.cs +++ b/src/Avalonia.Base/Layout/Layoutable.cs @@ -543,6 +543,8 @@ namespace Avalonia.Layout /// protected virtual Size MeasureCore(Size availableSize) { + ApplyStyling(); + if (IsVisible) { var margin = Margin; @@ -555,7 +557,6 @@ namespace Avalonia.Layout 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 007a35c077..63984592da 100644 --- a/src/Avalonia.Controls/StackPanel.cs +++ b/src/Avalonia.Controls/StackPanel.cs @@ -261,6 +261,9 @@ namespace Avalonia.Controls // Get next child. var child = children[i]; + // Measure the child. + child.Measure(layoutSlotSize); + bool isVisible = child.IsVisible; if (isVisible && !hasVisibleChild) @@ -268,8 +271,6 @@ namespace Avalonia.Controls 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 32c3e89b74..83c634d6ae 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 28ad64bac0..dfb8d38d20 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 @@ namespace Avalonia.Controls.UnitTests 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 ebd07d2596..ccc7e0ca0f 100644 --- a/tests/Avalonia.Controls.UnitTests/WindowTests.cs +++ b/tests/Avalonia.Controls.UnitTests/WindowTests.cs @@ -1642,6 +1642,83 @@ namespace Avalonia.Controls.UnitTests } } + [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)