diff --git a/samples/ControlCatalog/Pages/TextBoxPage.xaml b/samples/ControlCatalog/Pages/TextBoxPage.xaml index 346e561dfc..5c885ad091 100644 --- a/samples/ControlCatalog/Pages/TextBoxPage.xaml +++ b/samples/ControlCatalog/Pages/TextBoxPage.xaml @@ -96,6 +96,12 @@ + + + + + + + /// Defines how text is cased. + /// + public enum CharacterCasing + { + /// + /// The text casing is normal. + /// + Normal, + + /// + /// The text casing is upper. + /// + Upper, + + /// + /// The text casing is lower. + /// + Lower + } +} diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index eadb54b58a..7a93a813bc 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -159,6 +159,9 @@ namespace Avalonia.Controls public static readonly StyledProperty TextAlignmentProperty = TextBlock.TextAlignmentProperty.AddOwner(); + public static readonly StyledProperty CharacterCasingProperty = + AvaloniaProperty.Register(nameof(CharacterCasing), defaultValue: CharacterCasing.Normal); + /// /// Defines the property. /// @@ -455,6 +458,14 @@ namespace Avalonia.Controls set => SetValue(CaretIndexProperty, value); } + private void OnCharacterCasingChanged(AvaloniaPropertyChangedEventArgs e) + { + var tb = (TextBox)e.Sender; + var newValue = AdjustCasing(tb.Text, e.GetNewValue()); + + SetCurrentValue(TextProperty, newValue); + } + private void OnCaretIndexChanged(AvaloniaPropertyChangedEventArgs e) { UndoRedoState state; @@ -638,8 +649,8 @@ namespace Avalonia.Controls { SnapshotUndoRedo(); } - - return value; + + return AdjustCasing(value, textBox.CharacterCasing); } /// @@ -691,6 +702,15 @@ namespace Avalonia.Controls set => SetValue(TextAlignmentProperty, value); } + /// + /// Gets or sets the of the TextBox. + /// + public CharacterCasing CharacterCasing + { + get => GetValue(CharacterCasingProperty); + set => SetValue(CharacterCasingProperty, value); + } + /// /// Gets or sets the placeholder or descriptive text that is displayed even if the /// property is not yet set. @@ -1036,12 +1056,15 @@ namespace Avalonia.Controls CoerceValue(CaretIndexProperty); CoerceValue(SelectionStartProperty); CoerceValue(SelectionEndProperty); - RaiseTextChangeEvents(); UpdatePseudoclasses(); UpdateCommandStates(); } + else if (change.Property == CharacterCasingProperty) + { + OnCharacterCasingChanged(change); + } else if (change.Property == CaretIndexProperty) { OnCaretIndexChanged(change); @@ -1158,6 +1181,7 @@ namespace Avalonia.Controls } input = SanitizeInputText(input); + input = AdjustCasing(input, CharacterCasing); if (string.IsNullOrEmpty(input)) { @@ -2272,6 +2296,20 @@ namespace Avalonia.Controls return text.Substring(start, end - start); } + /// + /// Adjust the text casing. + /// + /// The text to adjust. + /// The character casing we want. + /// + private static string? AdjustCasing(string? text, CharacterCasing characterCasing) => characterCasing switch + { + CharacterCasing.Lower => text?.ToLower(System.Globalization.CultureInfo.CurrentCulture), + CharacterCasing.Upper => text?.ToUpper(System.Globalization.CultureInfo.CurrentCulture), + CharacterCasing.Normal => text, + _ => text + }; + /// /// Returns the sum of any vertical whitespace added between the and in the control template. /// diff --git a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs index fa578a7afe..a83b2c8b61 100644 --- a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs @@ -1517,6 +1517,37 @@ namespace Avalonia.Controls.UnitTests } } + [Theory] + [InlineData(CharacterCasing.Lower, "LoWer", "lower")] + [InlineData(CharacterCasing.Upper, "uppEr", "UPPER")] + [InlineData(CharacterCasing.Normal, "NorMal", "NorMal")] + public void Should_Respect_Casing(CharacterCasing casing, string value, string expected) + { + var target = new TextBox + { + Template = CreateTemplate(), + CharacterCasing = casing, + Text = value + }; + + Assert.Equal(target.Text, expected); + } + + [Fact] + public void Should_Update_Casing_After_First_Render() + { + var tb = new TextBox + { + Template = CreateTemplate(), + Text = "abc" + }; + + tb.Measure(Size.Infinity); + tb.CharacterCasing = CharacterCasing.Upper; + + Assert.Equal("ABC", tb.Text); + } + [Fact] public void Should_Move_Caret_To_EndOfLine() {