diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 6838f27262..fc94c6e908 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -396,6 +396,14 @@ namespace Avalonia.Controls get { return _newLine; } set { SetAndRaise(NewLineProperty, ref _newLine, value); } } + + /// + /// Clears the current selection, maintaining the + /// + public void ClearSelection() + { + SelectionStart = SelectionEnd = CaretIndex; + } /// /// Property for determining if the Cut command can be executed. @@ -479,8 +487,7 @@ namespace Avalonia.Controls if (ContextMenu == null || !ContextMenu.IsOpen) { - SelectionStart = 0; - SelectionEnd = 0; + ClearSelection(); RevealPassword = false; } @@ -512,7 +519,7 @@ namespace Avalonia.Controls text = Text ?? string.Empty; SetTextInternal(text.Substring(0, caretIndex) + input + text.Substring(caretIndex)); CaretIndex += input.Length; - SelectionStart = SelectionEnd = CaretIndex; + ClearSelection(); _undoRedoHelper.DiscardRedo(); } } @@ -737,7 +744,7 @@ namespace Avalonia.Controls SetTextInternal(text.Substring(0, caretIndex - removedCharacters) + text.Substring(caretIndex)); CaretIndex -= removedCharacters; - SelectionStart = SelectionEnd = CaretIndex; + ClearSelection(); } _undoRedoHelper.Snapshot(); @@ -810,7 +817,7 @@ namespace Avalonia.Controls } else if (movement) { - SelectionStart = SelectionEnd = CaretIndex; + ClearSelection(); } if (handled || movement) @@ -1117,7 +1124,8 @@ namespace Avalonia.Controls var end = Math.Max(selectionStart, selectionEnd); var text = Text; SetTextInternal(text.Substring(0, start) + text.Substring(end)); - SelectionStart = SelectionEnd = CaretIndex = start; + CaretIndex = start; + ClearSelection(); return true; } else @@ -1206,7 +1214,8 @@ namespace Avalonia.Controls set { Text = value.Text; - SelectionStart = SelectionEnd = CaretIndex = value.CaretPosition; + CaretIndex = value.CaretPosition; + ClearSelection(); } } } diff --git a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs index f41938a9bb..fe25fa7346 100644 --- a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs @@ -562,6 +562,41 @@ namespace Avalonia.Controls.UnitTests } } + [Fact] + public void TextBox_CaretIndex_Persists_When_Focus_Lost() + { + using (UnitTestApplication.Start(FocusServices)) + { + var target1 = new TextBox + { + Template = CreateTemplate(), + Text = "1234" + }; + var target2 = new TextBox + { + Template = CreateTemplate(), + Text = "5678" + }; + var sp = new StackPanel(); + sp.Children.Add(target1); + sp.Children.Add(target2); + + target1.ApplyTemplate(); + target2.ApplyTemplate(); + + var root = new TestRoot { Child = sp }; + + target2.Focus(); + target2.CaretIndex = 2; + Assert.False(target1.IsFocused); + Assert.True(target2.IsFocused); + + target1.Focus(); + + Assert.Equal(2, target2.CaretIndex); + } + } + [Fact] public void TextBox_Reveal_Password_Reset_When_Lost_Focus() {