瀏覽代碼

Improving TextBox behaviour on Ctrl+Backspace down event (#14138)

* Test: TextBox Ctrl+Back caret position

* Fixed: TextBox Ctrl+Back caret position

* Test: TextBox Ctrl+Back remove double whitespace

* Fixed: TextBox Ctrl+Back remove double whitespace

* Test: TextBox Ctrl+Back undo return caret position

* Fixed: TextBox Ctrl+Back undo return caret position
exGensImpl 1 年之前
父節點
當前提交
ac0f903052
共有 2 個文件被更改,包括 92 次插入9 次删除
  1. 19 9
      src/Avalonia.Controls/TextBox.cs
  2. 73 0
      tests/Avalonia.Controls.UnitTests/TextBoxTests.cs

+ 19 - 9
src/Avalonia.Controls/TextBox.cs

@@ -1307,13 +1307,13 @@ namespace Avalonia.Controls
                 {
                     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 @@ namespace Avalonia.Controls
         /// </summary>
         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 @@ namespace Avalonia.Controls
                 }
 
                 SetCurrentValue(SelectionEndProperty, SelectionEnd + offset);
+                
+                if (moveCaretPosition)
+                {
+                    _presenter.MoveCaretToTextPosition(SelectionEnd);
+                }
 
-                _presenter.MoveCaretToTextPosition(SelectionEnd);
-
-                if (!isSelecting)
+                if (!isSelecting && moveCaretPosition)
                 {
                     SetCurrentValue(CaretIndexProperty, SelectionEnd);
                 }
@@ -1976,7 +1979,7 @@ namespace Avalonia.Controls
 
                 _presenter?.MoveCaretToTextPosition(start);
 
-                SetCurrentValue(CaretIndexProperty, start);
+                SetCurrentValue(SelectionStartProperty, start);
 
                 ClearSelection();
 
@@ -2066,9 +2069,16 @@ namespace Avalonia.Controls
 
         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 @@ namespace Avalonia.Controls
 
             SetCurrentValue(SelectionStartProperty, CaretIndex);
 
-            MoveHorizontal(1, true, true);
+            MoveHorizontal(1, true, true, false);
 
             if (SelectionEnd < textLength && Text![SelectionEnd] == ' ')
             {

+ 73 - 0
tests/Avalonia.Controls.UnitTests/TextBoxTests.cs

@@ -151,6 +151,79 @@ namespace Avalonia.Controls.UnitTests
                 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()