Skip to content

Commit 526bca6

Browse files
authored
Merge pull request #19665 from ramezgerges/textbox_max_length
fix(TextBox): fix MaxLength to work correctly with paste
2 parents fc252c7 + 92f8302 commit 526bca6

File tree

3 files changed

+57
-15
lines changed

3 files changed

+57
-15
lines changed

src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBox.skia.cs

+35
Original file line numberDiff line numberDiff line change
@@ -4237,6 +4237,41 @@ public async Task When_Setting_Short_Text_And_Previous_Selection_Is_OutOfBounds(
42374237
SUT.RaiseEvent(UIElement.KeyUpEvent, new KeyRoutedEventArgs(SUT, VirtualKey.Escape, VirtualKeyModifiers.None));
42384238
}
42394239

4240+
[ConditionalTest(IgnoredPlatforms = RuntimeTestPlatforms.SkiaWasm)] // needs paste permission
4241+
public async Task When_MaxLine_Paste()
4242+
{
4243+
using var _ = new TextBoxFeatureConfigDisposable();
4244+
4245+
var SUT = new TextBox
4246+
{
4247+
MaxLength = 10,
4248+
Text = "0123456789",
4249+
SelectionStart = 4,
4250+
SelectionLength = 2
4251+
};
4252+
4253+
WindowHelper.WindowContent = SUT;
4254+
4255+
await WindowHelper.WaitForIdle();
4256+
await WindowHelper.WaitForLoaded(SUT);
4257+
4258+
SUT.Focus(FocusState.Programmatic);
4259+
await WindowHelper.WaitForIdle();
4260+
4261+
var dp = new DataPackage();
4262+
var text = "abcdefgh";
4263+
dp.SetText(text);
4264+
Clipboard.SetContent(dp);
4265+
await WindowHelper.WaitForIdle();
4266+
4267+
SUT.PasteFromClipboard();
4268+
await WindowHelper.WaitForIdle();
4269+
4270+
Assert.AreEqual("0123ab6789", SUT.Text);
4271+
Assert.AreEqual(6, SUT.SelectionStart);
4272+
Assert.AreEqual(0, SUT.SelectionLength);
4273+
}
4274+
42404275
private static bool HasColorInRectangle(RawBitmap screenshot, Rectangle rect, Color expectedColor)
42414276
{
42424277
for (var x = rect.Left; x < rect.Right; x++)

src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.cs

+20-13
Original file line numberDiff line numberDiff line change
@@ -419,20 +419,18 @@ private object CoerceText(object baseValue)
419419

420420
if (MaxLength > 0 && baseString.Length > MaxLength)
421421
{
422+
// Reject the new string if it's longer than the MaxLength
423+
#if __SKIA__
424+
_pendingSelection = null;
425+
#endif
422426
return DependencyProperty.UnsetValue;
423427
}
424428

425-
#if __SKIA__
426429
if (!AcceptsReturn)
427430
{
428431
baseString = GetFirstLine(baseString);
429-
if (_pendingSelection is { } selection)
430-
{
431-
var start = Math.Min(selection.start, baseString.Length);
432-
var end = Math.Min(selection.start + selection.length, baseString.Length);
433-
_pendingSelection = (start, end - start);
434-
}
435432
}
433+
#if __SKIA__
436434
else if (_isSkiaTextBox)
437435
{
438436
// WinUI replaces all \n's and and \r\n's by \r. This is annoying because
@@ -441,10 +439,13 @@ private object CoerceText(object baseValue)
441439
// the native input and the managed representation.
442440
baseString = RemoveLF(baseString);
443441
}
444-
#else
445-
if (!AcceptsReturn)
442+
443+
// make sure this coercion doesn't cause the pending selection to be out of range
444+
if (_pendingSelection is { } selection2)
446445
{
447-
baseString = GetFirstLine(baseString);
446+
var start = Math.Min(selection2.start, baseString.Length);
447+
var end = Math.Min(selection2.start + selection2.length, baseString.Length);
448+
_pendingSelection = (start, end - start);
448449
}
449450
#endif
450451

@@ -1430,15 +1431,21 @@ internal void PasteFromClipboard(string clipboardText)
14301431
var selectionStart = SelectionStart;
14311432
var selectionLength = SelectionLength;
14321433
var currentText = Text;
1434+
var adjustedClipboardText = clipboardText;
14331435

14341436
if (selectionLength > 0)
14351437
{
14361438
currentText = currentText.Remove(selectionStart, selectionLength);
14371439
}
14381440

1439-
currentText = currentText.Insert(selectionStart, clipboardText);
1441+
if (MaxLength > 0)
1442+
{
1443+
var clipboardRangeToBePasted = Math.Max(0, Math.Min(clipboardText.Length, MaxLength - currentText.Length));
1444+
adjustedClipboardText = clipboardText[..clipboardRangeToBePasted];
1445+
}
14401446

1441-
PasteFromClipboardPartial(clipboardText, selectionStart, selectionLength, currentText);
1447+
currentText = currentText.Insert(selectionStart, adjustedClipboardText);
1448+
PasteFromClipboardPartial(adjustedClipboardText, selectionStart, currentText);
14421449

14431450
#if __SKIA__
14441451
try
@@ -1468,7 +1475,7 @@ internal void PasteFromClipboard(string clipboardText)
14681475
#endif
14691476
}
14701477

1471-
partial void PasteFromClipboardPartial(string clipboardText, int selectionStart, int selectionLength, string newText);
1478+
partial void PasteFromClipboardPartial(string adjustedClipboardText, int selectionStart, string newText);
14721479

14731480
/// <summary>
14741481
/// Copies the selected content to the OS clipboard.

src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.skia.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1235,7 +1235,7 @@ private string RemoveLF(string baseString)
12351235
return baseString;
12361236
}
12371237

1238-
partial void PasteFromClipboardPartial(string clipboardText, int selectionStart, int selectionLength, string newText)
1238+
partial void PasteFromClipboardPartial(string adjustedClipboardText, int selectionStart, string newText)
12391239
{
12401240
if (_isSkiaTextBox)
12411241
{
@@ -1250,7 +1250,7 @@ partial void PasteFromClipboardPartial(string clipboardText, int selectionStart,
12501250
CommitAction(new ReplaceAction(Text, newText, selectionStart));
12511251
}
12521252

1253-
_pendingSelection = (selectionStart + clipboardText.Length, 0);
1253+
_pendingSelection = (selectionStart + adjustedClipboardText.Length, 0);
12541254
}
12551255
}
12561256

0 commit comments

Comments
 (0)