From 26bc22910f66d698a04419e737b8892eb34d60fa Mon Sep 17 00:00:00 2001 From: Dong Bin <14807942+rabbitism@users.noreply.github.com> Date: Wed, 22 Jan 2025 17:13:20 +0800 Subject: [PATCH] [TextBox] Add readonly property: LineCount. (#17656) * feat: add readonly property: LineCount. * feat: change property to method. --- src/Avalonia.Controls/TextBox.cs | 14 +++ .../TextBoxTests.cs | 100 ++++++++++++++++++ 2 files changed, 114 insertions(+) diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index b19c2eab27..39323d518b 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -823,6 +823,20 @@ namespace Avalonia.Controls private set => SetAndRaise(CanRedoProperty, ref _canRedo, value); } + /// + /// Get the number of lines in the TextBox. + /// + /// number of lines in the TextBox, or -1 if no layout information is available + /// + /// If Wrap == true, changing the width of the TextBox may change this value. + /// The value returned is the number of lines in the entire TextBox, regardless of how many are + /// currently in view. + /// + public int GetLineCount() + { + return this._presenter?.TextLayout.TextLines.Count ?? -1; + } + /// /// Raised when content is being copied to the clipboard /// diff --git a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs index 7aacaca174..e85aa99fc9 100644 --- a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs @@ -1235,6 +1235,106 @@ namespace Avalonia.Controls.UnitTests Assert.Equal((minLines * target.LineHeight) + textPresenterMargin.Top + textPresenterMargin.Bottom, scrollViewer.MinHeight); } } + + [Theory] + [InlineData(null, 1)] + [InlineData("", 1)] + [InlineData("Hello", 1)] + [InlineData("Hello\r\nWorld", 2)] + public void LineCount_Is_Correct(string? text, int lineCount) + { + using (UnitTestApplication.Start(Services)) + { + var target = new TextBox + { + Template = CreateTemplate(), + Text = text, + AcceptsReturn = true + }; + + var impl = CreateMockTopLevelImpl(); + var topLevel = new TestTopLevel(impl.Object) + { + Template = CreateTopLevelTemplate() + }; + topLevel.Content = target; + topLevel.ApplyTemplate(); + topLevel.LayoutManager.ExecuteInitialLayoutPass(); + + target.ApplyTemplate(); + target.Measure(Size.Infinity); + + Assert.Equal(lineCount, target.GetLineCount()); + } + } + + [Fact] + public void Unmeasured_TextBox_Has_Negative_LineCount() + { + var b = new TextBox(); + Assert.Equal(-1, b.GetLineCount()); + } + + [Fact] + public void LineCount_Is_Correct_After_Text_Change() + { + using (UnitTestApplication.Start(Services)) + { + var target = new TextBox + { + Template = CreateTemplate(), + Text = "Hello", + AcceptsReturn = true + }; + + var impl = CreateMockTopLevelImpl(); + var topLevel = new TestTopLevel(impl.Object) + { + Template = CreateTopLevelTemplate() + }; + topLevel.Content = target; + topLevel.ApplyTemplate(); + topLevel.LayoutManager.ExecuteInitialLayoutPass(); + + target.ApplyTemplate(); + target.Measure(Size.Infinity); + + Assert.Equal(1, target.GetLineCount()); + + target.Text = "Hello\r\nWorld"; + + Assert.Equal(2, target.GetLineCount()); + } + } + + [Fact] + public void Visible_LineCount_DoesNot_Affect_LineCount() + { + using (UnitTestApplication.Start(Services)) + { + var target = new TextBox + { + Template = CreateTemplate(), + Text = "Hello\r\nWorld\r\nHello\r\nAvalonia", + AcceptsReturn = true, + MaxLines = 2, + }; + + var impl = CreateMockTopLevelImpl(); + var topLevel = new TestTopLevel(impl.Object) + { + Template = CreateTopLevelTemplate() + }; + topLevel.Content = target; + topLevel.ApplyTemplate(); + topLevel.LayoutManager.ExecuteInitialLayoutPass(); + + target.ApplyTemplate(); + target.Measure(Size.Infinity); + + Assert.Equal(4, target.GetLineCount()); + } + } [Fact] public void CanUndo_CanRedo_Is_False_When_Initialized()