diff --git a/src/Controls/tests/DeviceTests/Elements/Editor/EditorTests.cs b/src/Controls/tests/DeviceTests/Elements/Editor/EditorTests.cs index 4ede41fb5134..39c6df536fa1 100644 --- a/src/Controls/tests/DeviceTests/Elements/Editor/EditorTests.cs +++ b/src/Controls/tests/DeviceTests/Elements/Editor/EditorTests.cs @@ -70,5 +70,30 @@ public async Task TextTransformUpdated(string text, TextTransform transform, str var platformText = await GetPlatformText(handler); Assert.Equal(expected, platformText); } + +#if WINDOWS + // Only Windows needs the IsReadOnly workaround for MaxLength==0 to prevent text from being entered + [Fact] + public async Task MaxLengthIsReadOnlyValueTest() + { + Editor editor = new Editor(); + + await InvokeOnMainThreadAsync(() => + { + var handler = CreateHandler(editor); + var platformControl = GetPlatformControl(handler); + + editor.MaxLength = 0; + Assert.True(platformControl.IsReadOnly); + editor.IsReadOnly = false; + Assert.True(platformControl.IsReadOnly); + + editor.MaxLength = 10; + Assert.False(platformControl.IsReadOnly); + editor.IsReadOnly = true; + Assert.True(platformControl.IsReadOnly); + }); + } +#endif } } diff --git a/src/Controls/tests/DeviceTests/Elements/Entry/EntryTests.cs b/src/Controls/tests/DeviceTests/Elements/Entry/EntryTests.cs index 779f48b08b1e..19f3cb6d4d88 100644 --- a/src/Controls/tests/DeviceTests/Elements/Entry/EntryTests.cs +++ b/src/Controls/tests/DeviceTests/Elements/Entry/EntryTests.cs @@ -79,5 +79,30 @@ await InvokeOnMainThreadAsync(() => Assert.Equal(0, cursorPosition); #endif } + +#if WINDOWS + // Only Windows needs the IsReadOnly workaround for MaxLength==0 to prevent text from being entered + [Fact] + public async Task MaxLengthIsReadOnlyValueTest() + { + Entry entry = new Entry(); + + await InvokeOnMainThreadAsync(() => + { + var handler = CreateHandler(entry); + var platformControl = GetPlatformControl(handler); + + entry.MaxLength = 0; + Assert.True(platformControl.IsReadOnly); + entry.IsReadOnly = false; + Assert.True(platformControl.IsReadOnly); + + entry.MaxLength = 10; + Assert.False(platformControl.IsReadOnly); + entry.IsReadOnly = true; + Assert.True(platformControl.IsReadOnly); + }); + } +#endif } } diff --git a/src/Controls/tests/DeviceTests/Elements/SearchBar/SearchBarTests.cs b/src/Controls/tests/DeviceTests/Elements/SearchBar/SearchBarTests.cs index 0f367651e0da..df848bde7163 100644 --- a/src/Controls/tests/DeviceTests/Elements/SearchBar/SearchBarTests.cs +++ b/src/Controls/tests/DeviceTests/Elements/SearchBar/SearchBarTests.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Microsoft.Maui.Controls; using Microsoft.Maui.Handlers; +using Microsoft.Maui.Platform; using Xunit; namespace Microsoft.Maui.DeviceTests @@ -28,5 +29,30 @@ public async Task TextTransformUpdated(string text, TextTransform transform, str var platformText = await GetPlatformText(handler); Assert.Equal(expected, platformText); } + +#if WINDOWS + // Only Windows needs the IsReadOnly workaround for MaxLength==0 to prevent text from being entered + [Fact] + public async Task MaxLengthIsReadOnlyValueTest() + { + SearchBar searchBar = new SearchBar(); + + await InvokeOnMainThreadAsync(() => + { + var handler = CreateHandler(searchBar); + var platformControl = GetPlatformControl(handler); + + searchBar.MaxLength = 0; + Assert.True(MauiAutoSuggestBox.GetIsReadOnly(platformControl)); + searchBar.IsReadOnly = false; + Assert.True(MauiAutoSuggestBox.GetIsReadOnly(platformControl)); + + searchBar.MaxLength = 10; + Assert.False(MauiAutoSuggestBox.GetIsReadOnly(platformControl)); + searchBar.IsReadOnly = true; + Assert.True(MauiAutoSuggestBox.GetIsReadOnly(platformControl)); + }); + } +#endif } } diff --git a/src/Core/src/Handlers/SearchBar/SearchBarHandler.Windows.cs b/src/Core/src/Handlers/SearchBar/SearchBarHandler.Windows.cs index 202aab62864b..b2eb3b8e6411 100644 --- a/src/Core/src/Handlers/SearchBar/SearchBarHandler.Windows.cs +++ b/src/Core/src/Handlers/SearchBar/SearchBarHandler.Windows.cs @@ -108,6 +108,7 @@ void OnLoaded(object sender, UI.Xaml.RoutedEventArgs e) PlatformView?.UpdatePlaceholderColor(VirtualView); PlatformView?.UpdateHorizontalTextAlignment(VirtualView); PlatformView?.UpdateMaxLength(VirtualView); + PlatformView?.UpdateIsReadOnly(VirtualView); } } diff --git a/src/Core/src/Platform/Android/EditTextExtensions.cs b/src/Core/src/Platform/Android/EditTextExtensions.cs index 9fc2f830615f..80b089d7c406 100644 --- a/src/Core/src/Platform/Android/EditTextExtensions.cs +++ b/src/Core/src/Platform/Android/EditTextExtensions.cs @@ -92,6 +92,9 @@ public static void UpdateMaxLength(this EditText editText, int maxLength) public static void SetLengthFilter(this EditText editText, int maxLength) { + if (maxLength == -1) + maxLength = int.MaxValue; + var currentFilters = new List(editText.GetFilters() ?? new IInputFilter[0]); var changed = false; @@ -105,7 +108,7 @@ public static void SetLengthFilter(this EditText editText, int maxLength) } } - if (maxLength > 0) + if (maxLength >= 0) { currentFilters.Add(new InputFilterLengthFilter(maxLength)); changed = true; diff --git a/src/Core/src/Platform/Windows/MauiAutoSuggestBox.cs b/src/Core/src/Platform/Windows/MauiAutoSuggestBox.cs new file mode 100644 index 000000000000..1c6713f55561 --- /dev/null +++ b/src/Core/src/Platform/Windows/MauiAutoSuggestBox.cs @@ -0,0 +1,34 @@ +#nullable enable +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; + +namespace Microsoft.Maui.Platform +{ + public static class MauiAutoSuggestBox + { + public static void InvalidateAttachedProperties(DependencyObject obj) + { + OnIsReadOnlyPropertyChanged(obj); + } + + // IsReadOnly + + public static bool GetIsReadOnly(DependencyObject obj) => + (bool)obj.GetValue(IsReadOnlyProperty); + + public static void SetIsReadOnly(DependencyObject obj, bool value) => + obj.SetValue(IsReadOnlyProperty, value); + + public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.RegisterAttached( + "IsReadOnly", typeof(bool), typeof(MauiTextBox), + new PropertyMetadata(true, OnIsReadOnlyPropertyChanged)); + + static void OnIsReadOnlyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs? e = null) + { + var element = d as FrameworkElement; + var textBox = element?.GetDescendantByName("TextBox"); + if (textBox != null) + textBox.IsReadOnly = true; + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Windows/SearchBarExtensions.cs b/src/Core/src/Platform/Windows/SearchBarExtensions.cs index f4d6ec938869..763857817e72 100644 --- a/src/Core/src/Platform/Windows/SearchBarExtensions.cs +++ b/src/Core/src/Platform/Windows/SearchBarExtensions.cs @@ -94,15 +94,25 @@ public static void UpdateVerticalTextAlignment(this AutoSuggestBox platformContr public static void UpdateMaxLength(this AutoSuggestBox platformControl, ISearchBar searchBar) { + var maxLength = searchBar.MaxLength; + + if (maxLength == -1) + maxLength = int.MaxValue; + + if (maxLength == 0) + MauiAutoSuggestBox.SetIsReadOnly(platformControl, true); + else + MauiAutoSuggestBox.SetIsReadOnly(platformControl, searchBar.IsReadOnly); + var currentControlText = platformControl.Text; - if (currentControlText.Length > searchBar.MaxLength) - platformControl.Text = currentControlText.Substring(0, searchBar.MaxLength); + if (currentControlText.Length > maxLength) + platformControl.Text = currentControlText.Substring(0, maxLength); } - + public static void UpdateIsReadOnly(this AutoSuggestBox platformControl, ISearchBar searchBar) { - platformControl.IsEnabled = searchBar.IsReadOnly; + MauiAutoSuggestBox.SetIsReadOnly(platformControl, searchBar.IsReadOnly); } public static void UpdateIsTextPredictionEnabled(this AutoSuggestBox platformControl, ISearchBar searchBar) diff --git a/src/Core/src/Platform/Windows/TextBoxExtensions.cs b/src/Core/src/Platform/Windows/TextBoxExtensions.cs index 7ad8851f05b4..b58415f5a404 100644 --- a/src/Core/src/Platform/Windows/TextBoxExtensions.cs +++ b/src/Core/src/Platform/Windows/TextBoxExtensions.cs @@ -128,6 +128,11 @@ public static void UpdateMaxLength(this TextBox textBox, ITextInput textInput) { var maxLength = textInput.MaxLength; + if (maxLength == 0) + textBox.IsReadOnly = true; + else + textBox.IsReadOnly = textInput.IsReadOnly; + if (maxLength == -1) maxLength = int.MaxValue;