Browse Source

[TextBox] Add readonly property: LineCount. (#17656)

* feat: add readonly property: LineCount.

* feat: change property to method.
Dong Bin 9 months ago
parent
commit
26bc22910f
2 changed files with 114 additions and 0 deletions
  1. 14 0
      src/Avalonia.Controls/TextBox.cs
  2. 100 0
      tests/Avalonia.Controls.UnitTests/TextBoxTests.cs

+ 14 - 0
src/Avalonia.Controls/TextBox.cs

@@ -823,6 +823,20 @@ namespace Avalonia.Controls
             private set => SetAndRaise(CanRedoProperty, ref _canRedo, value);
         }
 
+        /// <summary>
+        /// Get the number of lines in the TextBox.
+        /// </summary>
+        /// <value>number of lines in the TextBox, or -1 if no layout information is available</value>
+        /// <remarks>
+        /// 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.
+        /// </remarks>
+        public int GetLineCount()
+        {
+            return this._presenter?.TextLayout.TextLines.Count ?? -1;
+        }
+
         /// <summary>
         /// Raised when content is being copied to the clipboard
         /// </summary>

+ 100 - 0
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()