From cc4dbdaeb448851a88715af0db83ffc6baaa55ba Mon Sep 17 00:00:00 2001 From: Julien Lebosquain Date: Sat, 30 Nov 2024 15:21:32 +0100 Subject: [PATCH] Fix TextBlock re-measure in infinite container (#17638) * Add failing test for TextBlock * Fix TextBlock re-measure in infinite container * Fix outdated test --------- Co-authored-by: Max Katz --- src/Avalonia.Controls/SelectableTextBlock.cs | 6 +++-- src/Avalonia.Controls/TextBlock.cs | 15 +++++++++--- .../TextBlockTests.cs | 23 ++++++++++++++++++- 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/Avalonia.Controls/SelectableTextBlock.cs b/src/Avalonia.Controls/SelectableTextBlock.cs index 8f1248027c..b0fd78b321 100644 --- a/src/Avalonia.Controls/SelectableTextBlock.cs +++ b/src/Avalonia.Controls/SelectableTextBlock.cs @@ -224,12 +224,14 @@ namespace Avalonia.Controls textSource = new FormattedTextSource(text ?? "", defaultProperties, textStyleOverrides); } + var maxSize = GetMaxSizeFromConstraint(); + return new TextLayout( textSource, paragraphProperties, TextTrimming, - _constraint.Width, - _constraint.Height, + maxSize.Width, + maxSize.Height, MaxLines); } diff --git a/src/Avalonia.Controls/TextBlock.cs b/src/Avalonia.Controls/TextBlock.cs index 0afafe44b8..f6a0cdbdfd 100644 --- a/src/Avalonia.Controls/TextBlock.cs +++ b/src/Avalonia.Controls/TextBlock.cs @@ -162,7 +162,7 @@ namespace Avalonia.Controls nameof(Inlines), t => t.Inlines, (t, v) => t.Inlines = v); private TextLayout? _textLayout; - protected Size _constraint = Size.Infinity; + protected Size _constraint = new(double.NaN, double.NaN); protected IReadOnlyList? _textRuns; private InlineCollection? _inlines; @@ -366,6 +366,13 @@ namespace Avalonia.Controls internal bool HasComplexContent => Inlines != null && Inlines.Count > 0; + private protected Size GetMaxSizeFromConstraint() + { + var maxWidth = double.IsNaN(_constraint.Width) ? 0.0 : _constraint.Width; + var maxHeight = double.IsNaN(_constraint.Height) ? 0.0 : _constraint.Height; + return new Size(maxWidth, maxHeight); + } + /// /// The BaselineOffset property provides an adjustment to baseline offset /// @@ -670,12 +677,14 @@ namespace Avalonia.Controls textSource = new SimpleTextSource(text ?? "", defaultProperties); } + var maxSize = GetMaxSizeFromConstraint(); + return new TextLayout( textSource, paragraphProperties, TextTrimming, - _constraint.Width, - _constraint.Height, + maxSize.Width, + maxSize.Height, MaxLines); } diff --git a/tests/Avalonia.Controls.UnitTests/TextBlockTests.cs b/tests/Avalonia.Controls.UnitTests/TextBlockTests.cs index 3d7c6e6c1b..4a7281fae3 100644 --- a/tests/Avalonia.Controls.UnitTests/TextBlockTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TextBlockTests.cs @@ -1,3 +1,4 @@ +using System; using Avalonia.Controls.Documents; using Avalonia.Controls.Templates; using Avalonia.Data; @@ -33,7 +34,9 @@ namespace Avalonia.Controls.UnitTests { var textBlock = new TestTextBlock { Text = "Hello World" }; - Assert.Equal(Size.Infinity, textBlock.Constraint); + var constraint = textBlock.Constraint; + Assert.True(double.IsNaN(constraint.Width)); + Assert.True(double.IsNaN(constraint.Height)); textBlock.Measure(new Size(100, 100)); @@ -413,6 +416,24 @@ namespace Avalonia.Controls.UnitTests } } + [Fact] + public void TextBlock_With_Infinite_Size_Should_Be_Remeasured_After_TextLayout_Created() + { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + + var target = new TextBlock { Text = "" }; + var layout = target.TextLayout; + + Assert.Equal(0.0, layout.MaxWidth); + Assert.Equal(0.0, layout.MaxHeight); + + target.Text = "foo"; + target.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + + Assert.True(target.DesiredSize.Width > 0); + Assert.True(target.DesiredSize.Height > 0); + } + private class TestTextBlock : TextBlock { public Size Constraint => _constraint;