diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 7a271e8615..719e888dd4 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -202,6 +202,7 @@ namespace Avalonia.Controls { if (!_ignoreTextChanges) { + CaretIndex = CoerceCaretIndex(CaretIndex, value?.Length ?? 0); SetAndRaise(TextProperty, ref _text, value); } } @@ -558,10 +559,11 @@ namespace Avalonia.Controls return null; } - private int CoerceCaretIndex(int value) + private int CoerceCaretIndex(int value) => CoerceCaretIndex(value, Text?.Length ?? 0); + + private int CoerceCaretIndex(int value, int length) { var text = Text; - var length = text?.Length ?? 0; if (value < 0) { diff --git a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs index cff49bc32e..26fc2a2461 100644 --- a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs @@ -1,6 +1,8 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. +using System; +using System.Reactive.Linq; using Avalonia.Controls.Presenters; using Avalonia.Controls.Templates; using Avalonia.Data; @@ -200,6 +202,33 @@ namespace Avalonia.Controls.UnitTests } } + [Fact] + public void Setting_Text_Updates_CaretPosition() + { + using (UnitTestApplication.Start(Services)) + { + var target = new TextBox + { + Text = "Initial Text", + CaretIndex = 11 + }; + + var invoked = false; + + target.GetObservable(TextBox.TextProperty).Skip(1).Subscribe(_ => + { + // Caret index should be set before Text changed notification, as we don't want + // to notify with an invalid CaretIndex. + Assert.Equal(7, target.CaretIndex); + invoked = true; + }); + + target.Text = "Changed"; + + Assert.True(invoked); + } + } + private static TestServices Services => TestServices.MockThreadingInterface.With( standardCursorFactory: Mock.Of());