Sfoglia il codice sorgente

Merge pull request #5630 from luthfiampas/textbox-maxlength-respect-text-from-clipboard

TextBox.MaxLength should respect occurred text from clipboard
Steven Kirk 4 anni fa
parent
commit
9401668a7e

+ 29 - 14
src/Avalonia.Controls/TextBox.cs

@@ -514,21 +514,36 @@ namespace Avalonia.Controls
 
         private void HandleTextInput(string input)
         {
-            if (!IsReadOnly)
+            if (IsReadOnly)
             {
-                input = RemoveInvalidCharacters(input);
-                string text = Text ?? string.Empty;
-                int caretIndex = CaretIndex;
-                if (!string.IsNullOrEmpty(input) && (MaxLength == 0 || input.Length + text.Length - (Math.Abs(SelectionStart - SelectionEnd)) <= MaxLength))
-                {
-                    DeleteSelection();
-                    caretIndex = CaretIndex;
-                    text = Text ?? string.Empty;
-                    SetTextInternal(text.Substring(0, caretIndex) + input + text.Substring(caretIndex));
-                    CaretIndex += input.Length;
-                    ClearSelection();
-                    _undoRedoHelper.DiscardRedo();
-                }
+                return;
+            }
+            
+            input = RemoveInvalidCharacters(input);
+            
+            if (string.IsNullOrEmpty(input))
+            {
+                return;
+            }
+            
+            string text = Text ?? string.Empty;
+            int caretIndex = CaretIndex;
+            int newLength = input.Length + text.Length - Math.Abs(SelectionStart - SelectionEnd);
+            
+            if (MaxLength > 0 && newLength > MaxLength)
+            {
+                input = input.Remove(Math.Max(0, input.Length - (newLength - MaxLength)));
+            }
+            
+            if (!string.IsNullOrEmpty(input))
+            {
+                DeleteSelection();
+                caretIndex = CaretIndex;
+                text = Text ?? string.Empty;
+                SetTextInternal(text.Substring(0, caretIndex) + input + text.Substring(caretIndex));
+                CaretIndex += input.Length;
+                ClearSelection();
+                _undoRedoHelper.DiscardRedo();
             }
         }
 

+ 50 - 12
tests/Avalonia.Controls.UnitTests/TextBoxTests.cs

@@ -646,22 +646,49 @@ namespace Avalonia.Controls.UnitTests
                 Assert.Null(target.Text);
             }
         }
-
-        [Fact]
-        public void Text_Box_MaxLength_Work_Properly()
+        
+        [Theory]
+        [InlineData("abc", "d", 3, 0, 0, false, "abc")]
+        [InlineData("abc", "dd", 4, 3, 3, false, "abcd")]
+        [InlineData("abc", "ddd", 3, 0, 2, true, "ddc")]
+        [InlineData("abc", "dddd", 4, 1, 3, true, "addd")]
+        [InlineData("abc", "ddddd", 5, 3, 3, true, "abcdd")]
+        public void MaxLength_Works_Properly(
+            string initalText,
+            string textInput,
+            int maxLength,
+            int selectionStart,
+            int selectionEnd,
+            bool fromClipboard,
+            string expected)
         {
             using (UnitTestApplication.Start(Services))
             {
                 var target = new TextBox
                 {
                     Template = CreateTemplate(),
-                    Text = "abc",
-                    MaxLength = 3,
+                    Text = initalText,
+                    MaxLength = maxLength,
+                    SelectionStart = selectionStart,
+                    SelectionEnd = selectionEnd
                 };
-
-                RaiseKeyEvent(target, Key.D, KeyModifiers.None);
-
-                Assert.Equal("abc", target.Text);
+                
+                if (fromClipboard)
+                {
+                    AvaloniaLocator.CurrentMutable.Bind<IClipboard>().ToSingleton<ClipboardStub>();
+                    
+                    var clipboard = AvaloniaLocator.CurrentMutable.GetService<IClipboard>();
+                    clipboard.SetTextAsync(textInput).GetAwaiter().GetResult();
+                    
+                    RaiseKeyEvent(target, Key.V, KeyModifiers.Control);
+                    clipboard.ClearAsync().GetAwaiter().GetResult();
+                }
+                else
+                {
+                    RaiseTextEvent(target, textInput);
+                }
+                
+                Assert.Equal(expected, target.Text);
             }
         }
 
@@ -758,11 +785,22 @@ namespace Avalonia.Controls.UnitTests
 
         private class ClipboardStub : IClipboard // in order to get tests working that use the clipboard
         {
-            public Task<string> GetTextAsync() => Task.FromResult("");
+            private string _text;
+
+            public Task<string> GetTextAsync() => Task.FromResult(_text);
 
-            public Task SetTextAsync(string text) => Task.CompletedTask;
+            public Task SetTextAsync(string text)
+            {
+                _text = text;
+                return Task.CompletedTask;
+            }
 
-            public Task ClearAsync() => Task.CompletedTask;
+            public Task ClearAsync()
+            {
+                _text = null;
+                return Task.CompletedTask;
+            }
+            
             public Task SetDataObjectAsync(IDataObject data) => Task.CompletedTask;
 
             public Task<string[]> GetFormatsAsync() => Task.FromResult(Array.Empty<string>());