diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 8bd0286a0a0..431be00f4ea 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -1307,13 +1307,13 @@ protected override void OnKeyDown(KeyEventArgs e) { case Key.Left: selection = DetectSelection(); - MoveHorizontal(-1, hasWholeWordModifiers, selection); + MoveHorizontal(-1, hasWholeWordModifiers, selection, true); movement = true; break; case Key.Right: selection = DetectSelection(); - MoveHorizontal(1, hasWholeWordModifiers, selection); + MoveHorizontal(1, hasWholeWordModifiers, selection, true); movement = true; break; @@ -1781,7 +1781,7 @@ internal static int CoerceCaretIndex(AvaloniaObject sender, int value) /// public void Clear() => SetCurrentValue(TextProperty, string.Empty); - private void MoveHorizontal(int direction, bool wholeWord, bool isSelecting) + private void MoveHorizontal(int direction, bool wholeWord, bool isSelecting, bool moveCaretPosition) { if (_presenter == null) { @@ -1836,10 +1836,13 @@ private void MoveHorizontal(int direction, bool wholeWord, bool isSelecting) } SetCurrentValue(SelectionEndProperty, SelectionEnd + offset); + + if (moveCaretPosition) + { + _presenter.MoveCaretToTextPosition(SelectionEnd); + } - _presenter.MoveCaretToTextPosition(SelectionEnd); - - if (!isSelecting) + if (!isSelecting && moveCaretPosition) { SetCurrentValue(CaretIndexProperty, SelectionEnd); } @@ -1976,7 +1979,7 @@ internal bool DeleteSelection() _presenter?.MoveCaretToTextPosition(start); - SetCurrentValue(CaretIndexProperty, start); + SetCurrentValue(SelectionStartProperty, start); ClearSelection(); @@ -2066,9 +2069,16 @@ private void RaiseTextChangeEvents() private void SetSelectionForControlBackspace() { + var text = Text ?? string.Empty; var selectionStart = CaretIndex; - MoveHorizontal(-1, true, false); + MoveHorizontal(-1, true, false, false); + + if (SelectionEnd > 0 && + selectionStart < text.Length && text[selectionStart] == ' ') + { + SetCurrentValue(SelectionEndProperty, SelectionEnd - 1); + } SetCurrentValue(SelectionStartProperty, selectionStart); } @@ -2083,7 +2093,7 @@ private void SetSelectionForControlDelete() SetCurrentValue(SelectionStartProperty, CaretIndex); - MoveHorizontal(1, true, true); + MoveHorizontal(1, true, true, false); if (SelectionEnd < textLength && Text![SelectionEnd] == ' ') { diff --git a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs index 1ee154c44a8..a53d1dd5a10 100644 --- a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs @@ -151,6 +151,79 @@ public void CaretIndex_Can_Moved_To_Position_After_The_End_Of_Text_With_Arrow_Ke Assert.Equal(4, target.CaretIndex); } } + + [Fact] + public void Control_Backspace_Should_Set_Caret_Position_To_The_Start_Of_The_Deletion() + { + using (UnitTestApplication.Start(Services)) + { + var target = new TextBox + { + Template = CreateTemplate(), + Text = "First Second Third", + SelectionStart = 13, + SelectionEnd = 13 + }; + + target.CaretIndex = 10; + target.ApplyTemplate(); + + // (First Second |Third) + RaiseKeyEvent(target, Key.Back, KeyModifiers.Control); + // (First |Third) + + Assert.Equal(6, target.CaretIndex); + } + } + + [Fact] + public void Control_Backspace_Should_Remove_The_Double_Whitespace_If_Caret_Index_Was_At_The_End_Of_A_Word() + { + using (UnitTestApplication.Start(Services)) + { + var target = new TextBox + { + Template = CreateTemplate(), + Text = "First Second Third", + SelectionStart = 12, + SelectionEnd = 12 + }; + + target.ApplyTemplate(); + + // (First Second| Third) + RaiseKeyEvent(target, Key.Back, KeyModifiers.Control); + // (First| Third) + + Assert.Equal("First Third", target.Text); + } + } + + [Fact] + public void Control_Backspace_Undo_Should_Return_Caret_Position() + { + using (UnitTestApplication.Start(Services)) + { + var target = new TextBox + { + Template = CreateTemplate(), + Text = "First Second Third", + SelectionStart = 9, + SelectionEnd = 9 + }; + + target.ApplyTemplate(); + + // (First Second| Third) + RaiseKeyEvent(target, Key.Back, KeyModifiers.Control); + // (First| Third) + + target.Undo(); + // (First Second| Third) + + Assert.Equal(9, target.CaretIndex); + } + } [Fact] public void Press_Ctrl_A_Select_All_Text()