From ef37ef52b73221ebb241d3f697f4350acfd238ca Mon Sep 17 00:00:00 2001 From: mOlDaViA Date: Sat, 16 Mar 2024 15:56:46 +0100 Subject: [PATCH] Some code refactoring and cleanup. Using DPs SetCurrentValue instead of conditional access of some properties. Fixed password field not scrollable. --- src/Wpf.Ui/Controls/NumberBox/NumberBox.xaml | 16 +- .../Controls/PasswordBox/PasswordBox.cs | 180 ++++++++++-------- .../Controls/PasswordBox/PasswordBox.xaml | 46 ++++- src/Wpf.Ui/Controls/TextBox/TextBox.cs | 83 ++++---- src/Wpf.Ui/Controls/TextBox/TextBox.xaml | 4 +- src/Wpf.Ui/Controls/TitleBar/TitleBar.xaml | 4 +- src/Wpf.Ui/Wpf.Ui.csproj.DotSettings | 3 + 7 files changed, 197 insertions(+), 139 deletions(-) create mode 100644 src/Wpf.Ui/Wpf.Ui.csproj.DotSettings diff --git a/src/Wpf.Ui/Controls/NumberBox/NumberBox.xaml b/src/Wpf.Ui/Controls/NumberBox/NumberBox.xaml index b9788ab89..ecd0d2b64 100644 --- a/src/Wpf.Ui/Controls/NumberBox/NumberBox.xaml +++ b/src/Wpf.Ui/Controls/NumberBox/NumberBox.xaml @@ -54,10 +54,10 @@ + Foreground="{TemplateBinding Foreground}" + IsTabStop="False" /> + Foreground="{DynamicResource TextControlButtonForeground}" + IsTabStop="False"> @@ -179,8 +179,8 @@ VerticalAlignment="Top" Content="{TemplateBinding Icon}" FontSize="16" - IsTabStop="False" - Foreground="{TemplateBinding Foreground}" /> + Foreground="{TemplateBinding Foreground}" + IsTabStop="False" /> diff --git a/src/Wpf.Ui/Controls/PasswordBox/PasswordBox.cs b/src/Wpf.Ui/Controls/PasswordBox/PasswordBox.cs index e2bbbab26..bf72c1422 100644 --- a/src/Wpf.Ui/Controls/PasswordBox/PasswordBox.cs +++ b/src/Wpf.Ui/Controls/PasswordBox/PasswordBox.cs @@ -3,7 +3,9 @@ // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. +using System.Diagnostics; using System.Windows.Controls; +#pragma warning disable SA1124 // ReSharper disable once CheckNamespace namespace Wpf.Ui.Controls; @@ -13,7 +15,7 @@ namespace Wpf.Ui.Controls; /** * TextProperty contains asterisks OR raw password if IsPasswordRevealed is set to true * PasswordProperty always contains raw password - */ + **/ /// /// The modified password control. @@ -22,39 +24,33 @@ public class PasswordBox : Wpf.Ui.Controls.TextBox { private bool _lockUpdatingContents; - /// - /// Property for . - /// + #region Static Properties + + /// Identifies the dependency property. public static readonly DependencyProperty PasswordProperty = DependencyProperty.Register( nameof(Password), typeof(string), typeof(PasswordBox), - new PropertyMetadata(String.Empty, OnPasswordPropertyChanged) + new PropertyMetadata(String.Empty, OnPasswordChanged) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty PasswordCharProperty = DependencyProperty.Register( nameof(PasswordChar), typeof(char), typeof(PasswordBox), - new PropertyMetadata('*', OnPasswordCharPropertyChanged) + new PropertyMetadata('*', OnPasswordCharChanged) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty IsPasswordRevealedProperty = DependencyProperty.Register( nameof(IsPasswordRevealed), typeof(bool), typeof(PasswordBox), - new PropertyMetadata(false, OnPasswordRevealModePropertyChanged) + new PropertyMetadata(false, OnIsPasswordRevealedChanged) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty RevealButtonEnabledProperty = DependencyProperty.Register( nameof(RevealButtonEnabled), typeof(bool), @@ -62,9 +58,7 @@ public class PasswordBox : Wpf.Ui.Controls.TextBox new PropertyMetadata(true) ); - /// - /// Event for "Password has changed" - /// + /// Identifies the routed event. public static readonly RoutedEvent PasswordChangedEvent = EventManager.RegisterRoutedEvent( nameof(PasswordChanged), RoutingStrategy.Bubble, @@ -72,6 +66,55 @@ public class PasswordBox : Wpf.Ui.Controls.TextBox typeof(PasswordBox) ); + /// + /// Called when is changed. + /// + private static void OnPasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is not PasswordBox control) + { + return; + } + + control.OnPasswordChanged(); + } + + /// + /// Called if the character is changed in the during the run. + /// + private static void OnPasswordCharChanged( + DependencyObject d, + DependencyPropertyChangedEventArgs e + ) + { + if (d is not PasswordBox control) + { + return; + } + + control.OnPasswordCharChanged(); + } + + /// + /// Called if the reveal mode is changed in the during the run. + /// + private static void OnIsPasswordRevealedChanged( + DependencyObject d, + DependencyPropertyChangedEventArgs e + ) + { + if (d is not PasswordBox control) + { + return; + } + + control.OnPasswordRevealModeChanged(); + } + + #endregion + + #region Properties + /// /// Gets or sets currently typed text represented by asterisks. /// @@ -100,7 +143,7 @@ public bool IsPasswordRevealed } /// - /// Gets or sets a value deciding whether to display the reveal password button. + /// Gets or sets a value indicating whether to display the reveal password button. /// public bool RevealButtonEnabled { @@ -108,6 +151,10 @@ public bool RevealButtonEnabled set => SetValue(RevealButtonEnabledProperty, value); } + #endregion + + #region Public Events + /// /// Event fired from this text box when its inner content /// has been changed. @@ -121,10 +168,9 @@ public event RoutedEventHandler PasswordChanged remove => RemoveHandler(PasswordChangedEvent, value); } - public PasswordBox() - { - _lockUpdatingContents = false; - } + #endregion + + #region Protected Methods /// protected override void OnTextChanged(TextChangedEventArgs e) @@ -137,11 +183,15 @@ protected override void OnTextChanged(TextChangedEventArgs e) } else { - if (PlaceholderEnabled && Text.Length > 0) - PlaceholderEnabled = false; - - if (!PlaceholderEnabled && Text.Length < 1) - PlaceholderEnabled = true; + switch (PlaceholderEnabled) + { + case true when Text.Length > 0: + SetCurrentValue(PlaceholderEnabledProperty, false); + break; + case false when Text.Length < 1: + SetCurrentValue(PlaceholderEnabledProperty, true); + break; + } RevealClearButton(); } @@ -163,11 +213,13 @@ protected virtual void OnPasswordCharChanged() // If password is currently revealed, // do not replace displayed text with asterisks if (IsPasswordRevealed) + { return; + } _lockUpdatingContents = true; - Text = new String(PasswordChar, Password.Length); + SetCurrentValue(TextProperty, new string(PasswordChar, Password.Length)); _lockUpdatingContents = false; } @@ -176,7 +228,7 @@ protected virtual void OnPasswordRevealModeChanged() { _lockUpdatingContents = true; - Text = IsPasswordRevealed ? Password : new String(PasswordChar, Password.Length); + SetCurrentValue(TextProperty, IsPasswordRevealed ? Password : new string(PasswordChar, Password.Length)); _lockUpdatingContents = false; } @@ -184,9 +236,8 @@ protected virtual void OnPasswordRevealModeChanged() /// /// Triggered by clicking a button in the control template. /// - /// Sender of the click event. /// Additional parameters. - protected override void OnTemplateButtonClick(string parameter) + protected override void OnTemplateButtonClick(string? parameter) { #if DEBUG System.Diagnostics.Debug.WriteLine( @@ -198,7 +249,7 @@ protected override void OnTemplateButtonClick(string parameter) switch (parameter) { case "reveal": - IsPasswordRevealed = !IsPasswordRevealed; + SetCurrentValue(IsPasswordRevealedProperty, !IsPasswordRevealed); Focus(); CaretIndex = Text.Length; break; @@ -208,25 +259,33 @@ protected override void OnTemplateButtonClick(string parameter) } } + #endregion + + #region Private Methods + private void UpdateTextContents(bool isTriggeredByTextInput) { if (_lockUpdatingContents) + { return; + } if (IsPasswordRevealed) { if (Password == Text) + { return; + } _lockUpdatingContents = true; if (isTriggeredByTextInput) { - Password = Text; + SetCurrentValue(PasswordProperty, Text); } else { - Text = Password; + SetCurrentValue(TextProperty, Password); CaretIndex = Text.Length; } @@ -248,10 +307,12 @@ private void UpdateTextContents(bool isTriggeredByTextInput) var newCharacters = currentText.Replace(PasswordChar.ToString(), String.Empty); if (currentText.Length < currentPassword.Length) + { newPasswordValue = currentPassword.Remove( selectionIndex, currentPassword.Length - currentText.Length ); + } if (newCharacters.Length > 1) { @@ -264,10 +325,12 @@ private void UpdateTextContents(bool isTriggeredByTextInput) } else { - for (int i = 0; i < currentText.Length; i++) + for (var i = 0; i < currentText.Length; i++) { if (currentText[i] == PasswordChar) + { continue; + } newPasswordValue = currentText.Length == newPasswordValue.Length @@ -279,8 +342,8 @@ private void UpdateTextContents(bool isTriggeredByTextInput) _lockUpdatingContents = true; - Text = new String(PasswordChar, newPasswordValue.Length); - Password = newPasswordValue; + SetCurrentValue(TextProperty, new string(PasswordChar, newPasswordValue.Length)); + SetCurrentValue(PasswordProperty, newPasswordValue); CaretIndex = caretIndex; RaiseEvent(new RoutedEventArgs(PasswordChangedEvent)); @@ -288,42 +351,5 @@ private void UpdateTextContents(bool isTriggeredByTextInput) _lockUpdatingContents = false; } - /// - /// Called when is changed. - /// - private static void OnPasswordPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - if (d is not PasswordBox control) - return; - - control.OnPasswordChanged(); - } - - /// - /// Called if the character is changed in the during the run. - /// - private static void OnPasswordCharPropertyChanged( - DependencyObject d, - DependencyPropertyChangedEventArgs e - ) - { - if (d is not PasswordBox control) - return; - - control.OnPasswordCharChanged(); - } - - /// - /// Called if the reveal mode is changed in the during the run. - /// - private static void OnPasswordRevealModePropertyChanged( - DependencyObject d, - DependencyPropertyChangedEventArgs e - ) - { - if (d is not PasswordBox control) - return; - - control.OnPasswordRevealModeChanged(); - } + #endregion } diff --git a/src/Wpf.Ui/Controls/PasswordBox/PasswordBox.xaml b/src/Wpf.Ui/Controls/PasswordBox/PasswordBox.xaml index 6d02f27e8..fdef43fec 100644 --- a/src/Wpf.Ui/Controls/PasswordBox/PasswordBox.xaml +++ b/src/Wpf.Ui/Controls/PasswordBox/PasswordBox.xaml @@ -23,6 +23,22 @@ 24 14 + + @@ -69,11 +85,16 @@ Margin="{TemplateBinding Padding}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"> - + CanContentScroll="{TemplateBinding ScrollViewer.CanContentScroll}" + HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" + IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}" + IsTabStop="{TemplateBinding ScrollViewer.IsTabStop}" + Style="{StaticResource DefaultPasswordBoxScrollViewerStyle}" + TextElement.Foreground="{TemplateBinding Foreground}" + VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" /> @@ -174,11 +195,16 @@ TextElement.Foreground="{TemplateBinding Foreground}" /> - + CanContentScroll="{TemplateBinding ScrollViewer.CanContentScroll}" + HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" + IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}" + IsTabStop="{TemplateBinding ScrollViewer.IsTabStop}" + Style="{StaticResource DefaultPasswordBoxScrollViewerStyle}" + TextElement.Foreground="{TemplateBinding Foreground}" + VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" /> + Foreground="{DynamicResource TextControlButtonForeground}" + IsTabStop="False"> @@ -230,8 +256,8 @@ Command="{Binding Path=TemplateButtonCommand, RelativeSource={RelativeSource TemplatedParent}}" CommandParameter="reveal" Cursor="Arrow" - IsTabStop="False" - Foreground="{DynamicResource TextControlButtonForeground}"> + Foreground="{DynamicResource TextControlButtonForeground}" + IsTabStop="False"> diff --git a/src/Wpf.Ui/Controls/TextBox/TextBox.cs b/src/Wpf.Ui/Controls/TextBox/TextBox.cs index c528942f4..18dc56d47 100644 --- a/src/Wpf.Ui/Controls/TextBox/TextBox.cs +++ b/src/Wpf.Ui/Controls/TextBox/TextBox.cs @@ -7,6 +7,7 @@ using System.Windows.Controls; using Wpf.Ui.Converters; using Wpf.Ui.Input; +#pragma warning disable SA1124 // ReSharper disable once CheckNamespace namespace Wpf.Ui.Controls; @@ -18,9 +19,7 @@ public class TextBox : System.Windows.Controls.TextBox { #region Static properties - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty IconProperty = DependencyProperty.Register( nameof(Icon), typeof(IconElement), @@ -28,9 +27,7 @@ public class TextBox : System.Windows.Controls.TextBox new PropertyMetadata(null, null, IconSourceElementConverter.ConvertToIconElement) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty IconPlacementProperty = DependencyProperty.Register( nameof(IconPlacement), typeof(ElementPlacement), @@ -38,9 +35,7 @@ public class TextBox : System.Windows.Controls.TextBox new PropertyMetadata(ElementPlacement.Left) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty PlaceholderTextProperty = DependencyProperty.Register( nameof(PlaceholderText), typeof(string), @@ -48,9 +43,7 @@ public class TextBox : System.Windows.Controls.TextBox new PropertyMetadata(String.Empty) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty PlaceholderEnabledProperty = DependencyProperty.Register( nameof(PlaceholderEnabled), typeof(bool), @@ -58,9 +51,7 @@ public class TextBox : System.Windows.Controls.TextBox new PropertyMetadata(true) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty ClearButtonEnabledProperty = DependencyProperty.Register( nameof(ClearButtonEnabled), typeof(bool), @@ -68,9 +59,7 @@ public class TextBox : System.Windows.Controls.TextBox new PropertyMetadata(true) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty ShowClearButtonProperty = DependencyProperty.Register( nameof(ShowClearButton), typeof(bool), @@ -78,9 +67,7 @@ public class TextBox : System.Windows.Controls.TextBox new PropertyMetadata(false) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty IsTextSelectionEnabledProperty = DependencyProperty.Register( nameof(IsTextSelectionEnabled), typeof(bool), @@ -88,9 +75,7 @@ public class TextBox : System.Windows.Controls.TextBox new PropertyMetadata(false) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty TemplateButtonCommandProperty = DependencyProperty.Register( nameof(TemplateButtonCommand), typeof(IRelayCommand), @@ -105,14 +90,14 @@ public class TextBox : System.Windows.Controls.TextBox /// /// Gets or sets displayed . /// - public IconElement Icon + public IconElement? Icon { - get => (IconElement)GetValue(IconProperty); + get => (IconElement?)GetValue(IconProperty); set => SetValue(IconProperty, value); } /// - /// Defines which side the icon should be placed on. + /// Gets or sets on which side the icon should be placed on. /// public ElementPlacement IconPlacement { @@ -130,7 +115,7 @@ public string PlaceholderText } /// - /// Gets or sets a value determining whether to display the placeholder. + /// Gets or sets a value indicating whether to display the placeholder. /// public bool PlaceholderEnabled { @@ -139,7 +124,7 @@ public bool PlaceholderEnabled } /// - /// Gets or sets a value determining whether to enable the clear button. + /// Gets or sets a value indicating whether to enable the clear button. /// public bool ClearButtonEnabled { @@ -148,7 +133,7 @@ public bool ClearButtonEnabled } /// - /// Gets or sets a value determining whether to show the clear button when is focused. + /// Gets or sets a value indicating whether to show the clear button when is focused. /// public bool ShowClearButton { @@ -157,7 +142,7 @@ public bool ShowClearButton } /// - /// TODO + /// Gets or sets a value indicating whether text selection is enabled. /// public bool IsTextSelectionEnabled { @@ -172,24 +157,34 @@ public bool IsTextSelectionEnabled #endregion + #region Constructor + /// - /// Creates a new instance and assigns default events. + /// Initializes a new instance of the class. /// public TextBox() { SetValue(TemplateButtonCommandProperty, new RelayCommand(OnTemplateButtonClick)); } + #endregion + + #region Protected Methods + /// protected override void OnTextChanged(TextChangedEventArgs e) { base.OnTextChanged(e); - if (PlaceholderEnabled && Text.Length > 0) - PlaceholderEnabled = false; - - if (!PlaceholderEnabled && Text.Length < 1) - PlaceholderEnabled = true; + switch (PlaceholderEnabled) + { + case true when Text.Length > 0: + SetCurrentValue(PlaceholderEnabledProperty, false); + break; + case false when Text.Length < 1: + SetCurrentValue(PlaceholderEnabledProperty, true); + break; + } RevealClearButton(); } @@ -218,7 +213,9 @@ protected override void OnLostFocus(RoutedEventArgs e) protected void RevealClearButton() { if (ClearButtonEnabled && IsKeyboardFocusWithin) - ShowClearButton = Text.Length > 0; + { + SetCurrentValue(ShowClearButtonProperty, Text.Length > 0); + } } /// @@ -227,7 +224,9 @@ protected void RevealClearButton() protected void HideClearButton() { if (ClearButtonEnabled && !IsKeyboardFocusWithin && ShowClearButton) - ShowClearButton = false; + { + SetCurrentValue(ShowClearButtonProperty, false); + } } /// @@ -236,7 +235,9 @@ protected void HideClearButton() protected virtual void OnClearButtonClick() { if (Text.Length > 0) - Text = string.Empty; + { + SetCurrentValue(TextProperty, String.Empty); + } } /// @@ -248,4 +249,6 @@ protected virtual void OnTemplateButtonClick(string? parameter) OnClearButtonClick(); } + + #endregion } diff --git a/src/Wpf.Ui/Controls/TextBox/TextBox.xaml b/src/Wpf.Ui/Controls/TextBox/TextBox.xaml index bbfc4cca1..19c607104 100644 --- a/src/Wpf.Ui/Controls/TextBox/TextBox.xaml +++ b/src/Wpf.Ui/Controls/TextBox/TextBox.xaml @@ -206,8 +206,8 @@ BorderBrush="Transparent" Command="{Binding Path=TemplateButtonCommand, RelativeSource={RelativeSource TemplatedParent}}" Cursor="Arrow" - IsTabStop="False" - Foreground="{DynamicResource TextControlButtonForeground}"> + Foreground="{DynamicResource TextControlButtonForeground}" + IsTabStop="False"> diff --git a/src/Wpf.Ui/Controls/TitleBar/TitleBar.xaml b/src/Wpf.Ui/Controls/TitleBar/TitleBar.xaml index 110a281b8..7fb5c9862 100644 --- a/src/Wpf.Ui/Controls/TitleBar/TitleBar.xaml +++ b/src/Wpf.Ui/Controls/TitleBar/TitleBar.xaml @@ -183,8 +183,8 @@ x:Name="PART_CloseButton" Grid.Column="4" ButtonType="Close" - MouseOverButtonsForeground="White" - MouseOverBackground="{DynamicResource PaletteRedBrush}" /> + MouseOverBackground="{DynamicResource PaletteRedBrush}" + MouseOverButtonsForeground="White" /> diff --git a/src/Wpf.Ui/Wpf.Ui.csproj.DotSettings b/src/Wpf.Ui/Wpf.Ui.csproj.DotSettings new file mode 100644 index 000000000..40059e148 --- /dev/null +++ b/src/Wpf.Ui/Wpf.Ui.csproj.DotSettings @@ -0,0 +1,3 @@ + + True + True \ No newline at end of file