Skip to content

Commit b0f7646

Browse files
committed
feat: Implement TextBox.Select, TextBox.SelectAll on all platforms
1 parent 60d4a34 commit b0f7646

File tree

15 files changed

+149
-5
lines changed

15 files changed

+149
-5
lines changed

src/SamplesApp/UITests.Shared/UITests.Shared.projitems

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1789,6 +1789,10 @@
17891789
<SubType>Designer</SubType>
17901790
<Generator>MSBuild:Compile</Generator>
17911791
</Page>
1792+
<Page Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Controls\TextBox\TextBox_Selection.xaml">
1793+
<SubType>Designer</SubType>
1794+
<Generator>MSBuild:Compile</Generator>
1795+
</Page>
17921796
<Page Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Controls\TextBox\TextBox_TextChanging.xaml">
17931797
<SubType>Designer</SubType>
17941798
<Generator>MSBuild:Compile</Generator>
@@ -5471,6 +5475,9 @@
54715475
<Compile Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Controls\TextBox\TextBox_RoundedCorners.xaml.cs">
54725476
<DependentUpon>TextBox_RoundedCorners.xaml</DependentUpon>
54735477
</Compile>
5478+
<Compile Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Controls\TextBox\TextBox_Selection.xaml.cs">
5479+
<DependentUpon>TextBox_Selection.xaml</DependentUpon>
5480+
</Compile>
54745481
<Compile Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Controls\TextBox\TextBox_TextChanging.xaml.cs">
54755482
<DependentUpon>TextBox_TextChanging.xaml</DependentUpon>
54765483
</Compile>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<UserControl
2+
x:Class="UITests.Shared.Windows_UI_Xaml_Controls.TextBoxTests.TextBox_Selection"
3+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5+
xmlns:local="using:UITests.Windows_UI_Xaml_Controls.TextBox"
6+
xmlns:controls="using:Microsoft.UI.Xaml.Controls"
7+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
8+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
9+
mc:Ignorable="d"
10+
d:DesignHeight="300"
11+
d:DesignWidth="400">
12+
13+
<StackPanel>
14+
<controls:NumberBox x:Name="startNumber" PlaceholderText="Start" />
15+
<controls:NumberBox x:Name="lengthNumber" PlaceholderText="Length" />
16+
<TextBox x:Name="myTextBox" />
17+
<Button Click="Select_OnClick" Content="Select"></Button>
18+
<Button Click="SelectAll_OnClick" Content="Select all"></Button>
19+
</StackPanel>
20+
</UserControl>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using Uno.UI.Samples.Controls;
2+
using Windows.UI.Xaml;
3+
using Windows.UI.Xaml.Controls;
4+
using static Uno.UI.FeatureConfiguration;
5+
6+
7+
namespace UITests.Shared.Windows_UI_Xaml_Controls.TextBoxTests
8+
{
9+
[Sample("TextBox")]
10+
public sealed partial class TextBox_Selection : UserControl
11+
{
12+
public TextBox_Selection()
13+
{
14+
this.InitializeComponent();
15+
}
16+
private void Select_OnClick(object sender, RoutedEventArgs args)
17+
{
18+
myTextBox.Focus(FocusState.Programmatic);
19+
myTextBox.Select((int)startNumber.Value, (int)lengthNumber.Value);
20+
}
21+
22+
private void SelectAll_OnClick(object sender, RoutedEventArgs args)
23+
{
24+
myTextBox.Focus(FocusState.Programmatic);
25+
myTextBox.SelectAll();
26+
}
27+
}
28+
}

src/Uno.UI.Runtime.Skia.Gtk/UI/Xaml/Controls/TextBoxViewExtension.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,5 +288,14 @@ public void SetIsPassword(bool isPassword)
288288
entry.Visibility = !isPassword;
289289
}
290290
}
291+
292+
public void Select(int start, int length)
293+
{
294+
if (_currentInputWidget is Entry entry)
295+
{
296+
entry.SelectRegion(start_pos: start, end_pos: start + length);
297+
}
298+
// TODO: Handle TextView..
299+
}
291300
}
292301
}

src/Uno.UI.Runtime.Skia.Wpf/Extensions/UI/Xaml/Controls/TextBoxViewExtension.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,5 +187,7 @@ public void SetIsPassword(bool isPassword)
187187
{
188188
// No support for now.
189189
}
190+
191+
public void Select(int start, int length) => _currentInputWidget?.Select(start, length);
190192
}
191193
}

src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/TextBox.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -463,14 +463,14 @@ public bool CanUndo
463463
// Forced skipping of method Windows.UI.Xaml.Controls.TextBox.SelectionChanged.remove
464464
// Forced skipping of method Windows.UI.Xaml.Controls.TextBox.ContextMenuOpening.add
465465
// Forced skipping of method Windows.UI.Xaml.Controls.TextBox.ContextMenuOpening.remove
466-
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
466+
#if false || false || false || false || false || false || false
467467
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
468468
public void Select( int start, int length)
469469
{
470470
global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.UI.Xaml.Controls.TextBox", "void TextBox.Select(int start, int length)");
471471
}
472472
#endif
473-
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
473+
#if false || false || false || false || false || false || false
474474
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
475475
public void SelectAll()
476476
{

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,7 @@ internal interface ITextBoxViewExtension
1717
void SetTextNative(string text);
1818

1919
void SetIsPassword(bool isPassword);
20+
21+
void Select(int start, int length);
2022
}
2123
}

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ public ImeAction ImeOptions
122122
set { this.SetValue(ImeOptionsProperty, value); }
123123
}
124124

125-
public static DependencyProperty ImeOptionsProperty { get ; } =
125+
public static DependencyProperty ImeOptionsProperty { get; } =
126126
DependencyProperty.Register("ImeOptions",
127127
typeof(ImeAction),
128128
typeof(TextBox),
@@ -188,6 +188,11 @@ public override bool RequestFocus(FocusSearchDirection direction, Rect previousl
188188
}
189189
}
190190

191+
partial void SelectPartial(int start, int length)
192+
=> _textBoxView.SetSelection(start: start, stop: start + length);
193+
194+
public void SelectAll() => _textBoxView.SelectAll();
195+
191196
/// <summary>
192197
/// Applies PreventKeyboardDisplayOnProgrammaticFocus by temporarily disabling soft input display.
193198
/// </summary>

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,37 @@ protected override void OnVerticalContentAlignmentChanged(VerticalAlignment oldV
762762

763763
partial void OnVerticalContentAlignmentChangedPartial(VerticalAlignment oldVerticalContentAlignment, VerticalAlignment newVerticalContentAlignment);
764764

765+
public void Select(int start, int length)
766+
{
767+
if (start < 0)
768+
{
769+
throw new ArgumentOutOfRangeException(nameof(start), $"'{start}' cannot be negative.");
770+
}
771+
772+
if (length < 0)
773+
{
774+
throw new ArgumentOutOfRangeException(nameof(length), $"'{length}' cannot be negative.");
775+
}
776+
777+
// TODO: Test and adjust (if needed) this logic for surrogate pairs.
778+
779+
var textLength = Text.Length;
780+
781+
if (start >= textLength)
782+
{
783+
start = textLength;
784+
length = 0;
785+
}
786+
else if (start + length > textLength)
787+
{
788+
length = textLength - start;
789+
}
790+
791+
SelectPartial(start, length);
792+
}
793+
794+
partial void SelectPartial(int start, int length);
795+
765796
internal override bool CanHaveChildren() => true;
766797
}
767798
}

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,14 @@ partial void OnTextAlignmentChangedPartial(DependencyPropertyChangedEventArgs e)
7171
_textBoxView?.UpdateTextAlignment();
7272
}
7373

74+
partial void SelectPartial(int start, int length)
75+
{
76+
if (_textBoxView != null)
77+
{
78+
_textBoxView.SelectedTextRange = _textBoxView.GetTextRange(start: start, end: start + length);
79+
}
80+
}
81+
7482
internal MultilineTextBoxView MultilineTextBox
7583
{
7684
get
@@ -267,7 +275,7 @@ public UIReturnKeyType ReturnKeyType
267275
set { SetValue(ReturnKeyTypeProperty, value); }
268276
}
269277

270-
public static DependencyProperty ReturnKeyTypeProperty { get ; } =
278+
public static DependencyProperty ReturnKeyTypeProperty { get; } =
271279
DependencyProperty.Register(
272280
"ReturnKeyType",
273281
typeof(UIReturnKeyType),
@@ -304,7 +312,7 @@ public UIKeyboardAppearance KeyboardAppearance
304312
set { SetValue(KeyboardAppearanceProperty, value); }
305313
}
306314

307-
public static DependencyProperty KeyboardAppearanceProperty { get ; } =
315+
public static DependencyProperty KeyboardAppearanceProperty { get; } =
308316
DependencyProperty.Register(
309317
"KeyboardAppearance",
310318
typeof(UIKeyboardAppearance),

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@ partial void OnTextAlignmentChangedPartial(DependencyPropertyChangedEventArgs e)
6363
{
6464
}
6565

66+
partial void SelectPartial(int start, int length)
67+
{
68+
if (_textBoxView != null)
69+
{
70+
_textBoxView.SelectedTextRange = _textBoxView.GetTextRange(start: start, end: start + length);
71+
}
72+
}
73+
6674
private void UpdateTextBoxView()
6775
{
6876
if (_contentElement != null)

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ private void UpdateTextBoxView()
2323

2424
partial void OnFocusStateChangedPartial(FocusState focusState) => _textBoxView?.OnFocusStateChanged(focusState);
2525

26+
partial void SelectPartial(int start, int length)
27+
{
28+
_textBoxView?.Select(start, length);
29+
}
30+
31+
public void SelectAll() => Select(0, Text.Length);
32+
2633
protected void SetIsPassword(bool isPassword) => _textBoxView?.SetIsPassword(isPassword);
2734
}
2835
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Uno.Extensions;
2+
using Uno.Foundation;
23
using Windows.UI.Xaml.Input;
34
using Windows.UI.Xaml.Media;
45

@@ -116,6 +117,13 @@ partial void OnIsReadonlyChangedPartial(DependencyPropertyChangedEventArgs e)
116117

117118
private void ApplyIsReadonly(bool? isReadOnly = null) => _textBoxView?.SetIsReadOnly(isReadOnly ?? IsReadOnly);
118119

120+
partial void SelectPartial(int start, int length)
121+
{
122+
_textBoxView?.Select(start, length);
123+
}
124+
125+
public void SelectAll() => Select(0, Text.Length);
126+
119127
public int SelectionStart
120128
{
121129
get => _textBoxView?.SelectionStart ?? 0;

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ internal void SetTextNative(string text)
6363
_textBoxExtension?.SetTextNative(text);
6464
}
6565

66+
internal void Select(int start, int length)
67+
{
68+
_textBoxExtension.Select(start, length);
69+
}
70+
6671
internal void OnForegroundChanged(Brush brush) => DisplayBlock.Foreground = brush;
6772

6873
internal void OnFocusStateChanged(FocusState focusState)

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Windows.Foundation;
99
using System.Globalization;
1010
using Uno.Disposables;
11+
using Uno.Foundation;
1112

1213
namespace Windows.UI.Xaml.Controls
1314
{
@@ -105,6 +106,9 @@ internal void SetTextNative(string text)
105106
InvalidateMeasure();
106107
}
107108

109+
internal void Select(int start, int length)
110+
=> WebAssemblyRuntime.InvokeJS($"document.getElementById({HtmlId}).setSelectionRange({start}, {start + length})");
111+
108112
protected override Size MeasureOverride(Size availableSize) => MeasureView(availableSize);
109113

110114
internal void SetIsPassword(bool isPassword)

0 commit comments

Comments
 (0)