优化更新代码,添加界面功能并整合
This commit is contained in:
281
WPFluent/Controls/PasswordBox/PasswordBox.cs
Normal file
281
WPFluent/Controls/PasswordBox/PasswordBox.cs
Normal file
@@ -0,0 +1,281 @@
|
||||
|
||||
|
||||
|
||||
// TODO: This is an initial implementation and requires the necessary corrections, tests and adjustments.
|
||||
|
||||
/* TextProperty contains asterisks OR raw password if IsPasswordRevealed is set to true
|
||||
PasswordProperty always contains raw password */
|
||||
|
||||
|
||||
using System.Windows.Controls;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace WPFluent.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// The modified password control.
|
||||
/// </summary>
|
||||
public partial class PasswordBox : WPFluent.Controls.TextBox
|
||||
{
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="IsPasswordRevealed"/> dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsPasswordRevealedProperty = DependencyProperty.Register(
|
||||
nameof(IsPasswordRevealed),
|
||||
typeof(bool),
|
||||
typeof(PasswordBox),
|
||||
new PropertyMetadata(false, OnIsPasswordRevealedChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="PasswordChanged"/> routed event.
|
||||
/// </summary>
|
||||
public static readonly RoutedEvent PasswordChangedEvent = EventManager.RegisterRoutedEvent(
|
||||
nameof(PasswordChanged),
|
||||
RoutingStrategy.Bubble,
|
||||
typeof(RoutedEventHandler),
|
||||
typeof(PasswordBox));
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="PasswordChar"/> dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty PasswordCharProperty = DependencyProperty.Register(
|
||||
nameof(PasswordChar),
|
||||
typeof(char),
|
||||
typeof(PasswordBox),
|
||||
new PropertyMetadata('*', OnPasswordCharChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="Password"/> dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty PasswordProperty = DependencyProperty.Register(
|
||||
nameof(Password),
|
||||
typeof(string),
|
||||
typeof(PasswordBox),
|
||||
new PropertyMetadata(string.Empty, OnPasswordChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="RevealButtonEnabled"/> dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty RevealButtonEnabledProperty = DependencyProperty.Register(
|
||||
nameof(RevealButtonEnabled),
|
||||
typeof(bool),
|
||||
typeof(PasswordBox),
|
||||
new PropertyMetadata(true));
|
||||
private bool _lockUpdatingContents;
|
||||
private readonly PasswordHelper _passwordHelper;
|
||||
|
||||
public PasswordBox()
|
||||
{
|
||||
_lockUpdatingContents = false;
|
||||
_passwordHelper = new PasswordHelper(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event fired from this text box when its inner content has been changed.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// It is redirected from inner TextContainer.Changed event.
|
||||
/// </remarks>
|
||||
public event RoutedEventHandler PasswordChanged
|
||||
{
|
||||
add => AddHandler(PasswordChangedEvent, value);
|
||||
remove => RemoveHandler(PasswordChangedEvent, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called if the reveal mode is changed in the during the run.
|
||||
/// </summary>
|
||||
private static void OnIsPasswordRevealedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if(d is not PasswordBox control)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
control.OnPasswordRevealModeChanged();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when <see cref="Password"/> is changed.
|
||||
/// </summary>
|
||||
private static void OnPasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if(d is not PasswordBox control)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
control.OnPasswordChanged();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called if the character is changed in the during the run.
|
||||
/// </summary>
|
||||
private static void OnPasswordCharChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if(d is not PasswordBox control)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
control.OnPasswordCharChanged();
|
||||
}
|
||||
|
||||
private void UpdateTextContents(bool isTriggeredByTextInput)
|
||||
{
|
||||
if(_lockUpdatingContents)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(IsPasswordRevealed)
|
||||
{
|
||||
if(Password == Text)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_lockUpdatingContents = true;
|
||||
|
||||
if(isTriggeredByTextInput)
|
||||
{
|
||||
SetCurrentValue(PasswordProperty, Text);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCurrentValue(TextProperty, Password);
|
||||
CaretIndex = Text.Length;
|
||||
}
|
||||
|
||||
RaiseEvent(new RoutedEventArgs(PasswordChangedEvent));
|
||||
|
||||
_lockUpdatingContents = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var caretIndex = CaretIndex;
|
||||
var newPasswordValue = _passwordHelper.GetPassword();
|
||||
|
||||
if(isTriggeredByTextInput)
|
||||
{
|
||||
newPasswordValue = _passwordHelper.GetNewPassword();
|
||||
}
|
||||
|
||||
_lockUpdatingContents = true;
|
||||
|
||||
SetCurrentValue(TextProperty, new string(PasswordChar, newPasswordValue.Length));
|
||||
SetCurrentValue(PasswordProperty, newPasswordValue);
|
||||
CaretIndex = caretIndex;
|
||||
|
||||
RaiseEvent(new RoutedEventArgs(PasswordChangedEvent));
|
||||
|
||||
_lockUpdatingContents = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is called when <see cref="Password"/> property is changing.
|
||||
/// </summary>
|
||||
protected virtual void OnPasswordChanged() { UpdateTextContents(false); }
|
||||
|
||||
/// <summary>
|
||||
/// Is called when <see cref="PasswordChar"/> property is changing.
|
||||
/// </summary>
|
||||
protected virtual void OnPasswordCharChanged()
|
||||
{
|
||||
// If password is currently revealed,
|
||||
// do not replace displayed text with asterisks
|
||||
if(IsPasswordRevealed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_lockUpdatingContents = true;
|
||||
|
||||
SetCurrentValue(TextProperty, new string(PasswordChar, Password.Length));
|
||||
|
||||
_lockUpdatingContents = false;
|
||||
}
|
||||
|
||||
protected virtual void OnPasswordRevealModeChanged()
|
||||
{
|
||||
_lockUpdatingContents = true;
|
||||
|
||||
SetCurrentValue(TextProperty, IsPasswordRevealed ? Password : new string(PasswordChar, Password.Length));
|
||||
|
||||
_lockUpdatingContents = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triggered by clicking a button in the control template.
|
||||
/// </summary>
|
||||
/// <param name="parameter">Additional parameters.</param>
|
||||
protected override void OnTemplateButtonClick(string? parameter)
|
||||
{
|
||||
System.Diagnostics.Debug
|
||||
.WriteLine(
|
||||
$"INFO: {typeof(PasswordBox)} button clicked with param: {parameter}",
|
||||
"WPFluent.PasswordBox");
|
||||
|
||||
switch(parameter)
|
||||
{
|
||||
case "reveal":
|
||||
SetCurrentValue(IsPasswordRevealedProperty, !IsPasswordRevealed);
|
||||
_ = Focus();
|
||||
CaretIndex = Text.Length;
|
||||
break;
|
||||
default:
|
||||
base.OnTemplateButtonClick(parameter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void OnTextChanged(TextChangedEventArgs e)
|
||||
{
|
||||
UpdateTextContents(true);
|
||||
|
||||
if(_lockUpdatingContents)
|
||||
{
|
||||
base.OnTextChanged(e);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetPlaceholderTextVisibility();
|
||||
|
||||
RevealClearButton();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the password is revealed.
|
||||
/// </summary>
|
||||
public bool IsPasswordRevealed
|
||||
{
|
||||
get => (bool)GetValue(IsPasswordRevealedProperty);
|
||||
private set => SetValue(IsPasswordRevealedProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets currently typed text represented by asterisks.
|
||||
/// </summary>
|
||||
public string Password { get => (string)GetValue(PasswordProperty); set => SetValue(PasswordProperty, value); }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets character used to mask the password.
|
||||
/// </summary>
|
||||
public char PasswordChar
|
||||
{
|
||||
get => (char)GetValue(PasswordCharProperty);
|
||||
set => SetValue(PasswordCharProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to display the password reveal button.
|
||||
/// </summary>
|
||||
public bool RevealButtonEnabled
|
||||
{
|
||||
get => (bool)GetValue(RevealButtonEnabledProperty);
|
||||
set => SetValue(RevealButtonEnabledProperty, value);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user