diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs
index e246d48831..5d2b7bcb53 100644
--- a/src/Avalonia.Controls/TextBox.cs
+++ b/src/Avalonia.Controls/TextBox.cs
@@ -1877,6 +1877,28 @@ namespace Avalonia.Controls
_scrollViewer?.PageDown();
}
+ ///
+ /// Scroll the to the specified line index.
+ ///
+ /// The line index to scroll to.
+ /// is less than zero. -or - is larger than or equal to the line count.
+ public void ScrollToLine(int lineIndex)
+ {
+ if (_presenter is null)
+ {
+ return;
+ }
+
+ if (lineIndex < 0 || lineIndex >= _presenter.TextLayout.TextLines.Count)
+ {
+ throw new ArgumentOutOfRangeException(nameof(lineIndex));
+ }
+
+ var textLine = _presenter.TextLayout.TextLines[lineIndex];
+ _presenter.MoveCaretToTextPosition(textLine.FirstTextSourceIndex);
+
+ }
+
///
/// Select all text in the TextBox
///
diff --git a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs
index 3c7fb6f9c0..1ee154c44a 100644
--- a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs
@@ -1182,6 +1182,47 @@ namespace Avalonia.Controls.UnitTests
}
}
+ [Theory]
+ [InlineData("A\nBB\nCCC\nDDDD", 0, 0)]
+ [InlineData("A\nBB\nCCC\nDDDD", 1, 2)]
+ [InlineData("A\nBB\nCCC\nDDDD", 2, 5)]
+ [InlineData("A\nBB\nCCC\nDDDD", 3, 9)]
+ [InlineData("واحد\nاثنين\nثلاثة\nأربعة", 0, 0)]
+ [InlineData("واحد\nاثنين\nثلاثة\nأربعة", 1, 5)]
+ [InlineData("واحد\nاثنين\nثلاثة\nأربعة", 2, 11)]
+ [InlineData("واحد\nاثنين\nثلاثة\nأربعة", 3, 17)]
+ public void Should_Scroll_Caret_To_Line(string text, int targetLineIndex, int expectedCaretIndex)
+ {
+ using (UnitTestApplication.Start(Services))
+ {
+ var tb = new TextBox
+ {
+ Template = CreateTemplate(),
+ Text = text
+ };
+ tb.ApplyTemplate();
+ tb.ScrollToLine(targetLineIndex);
+ Assert.Equal(expectedCaretIndex, tb.CaretIndex);
+ }
+ }
+
+ [Fact]
+ public void Should_Throw_ArgumentOutOfRange()
+ {
+ using (UnitTestApplication.Start(Services))
+ {
+ var tb = new TextBox
+ {
+ Template = CreateTemplate(),
+ Text = string.Empty
+ };
+ tb.ApplyTemplate();
+
+ Assert.Throws(() => tb.ScrollToLine(-1));
+ Assert.Throws(() => tb.ScrollToLine(1));
+ }
+ }
+
private static TestServices FocusServices => TestServices.MockThreadingInterface.With(
focusManager: new FocusManager(),
keyboardDevice: () => new KeyboardDevice(),