using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
namespace PasswordTest
{
/// <summary>
/// 顯示最后一個(gè)字符的密碼輸入框
/// </summary>
public class BlinkPasswordBox : TextBox
{
#region DependencyProperty
public static readonly DependencyProperty PasswordCharProperty = DependencyProperty.RegisterAttached("PasswordChar", typeof(char), typeof(BlinkPasswordBox), new FrameworkPropertyMetadata('●'));
/// <summary>
/// 密文字符
/// </summary>
public char PasswordChar
{
get { return (char)GetValue(PasswordCharProperty); }
set { SetValue(PasswordCharProperty, value); }
}
public static readonly DependencyProperty PasswordProperty = DependencyProperty.RegisterAttached("Password", typeof(string), typeof(BlinkPasswordBox), new UIPropertyMetadata(""));
/// <summary>
/// 密碼字符
/// </summary>
public string Password
{
get { return (string)GetValue(PasswordProperty); }
set { SetValue(PasswordProperty, value); }
}
#endregion
#region Properties
/// <summary>
/// 最后的光標(biāo)位置
/// </summary>
private int mLastStart = 0;
/// <summary>
/// 明文消失的時(shí)間
/// </summary>
private int mDelay = 1000;
/// <summary>
/// 定時(shí)Token
/// </summary>
private CancellationTokenSource mWaitToken = new CancellationTokenSource();
/// <summary>
/// 密碼
/// </summary>
private string mPassword = string.Empty;
/// <summary>
/// 正在更新文本
/// </summary>
private bool IsUpdating;
/// <summary>
/// 顯示的文本
/// </summary>
private string ShowText
{
get { return base.Text; }
set
{
IsUpdating = true;
base.Text = value;
IsUpdating = false;
}
}
/// <summary>
/// 密碼設(shè)置
/// </summary>
public new string Text
{
get { return mPassword; }
set
{
mPassword = value;
this.ShowText = new string(PasswordChar, value.Length);
}
}
#endregion
#region protected override
protected override void OnTextChanged(TextChangedEventArgs e)
{
if (IsUpdating == true)
return;
string currentText = this.ShowText;
int start = this.SelectionStart;
RemoveChar(currentText, start);
SetShowText(currentText, start);
base.OnTextChanged(e);
}
/// <summary>
/// 設(shè)置要顯示的文本
/// </summary>
/// <param name="e"></param>
/// <param name="currentText"></param>
/// <param name="start"></param>
private void SetShowText(string currentText, int start)
{
if (!string.IsNullOrEmpty(currentText))
{
string addChar = string.Empty;
for (int i = 0; i < currentText.Length; i++)
{
if (currentText[i] != PasswordChar)
{
addChar = currentText[i].ToString();
if (this.ShowText.Length == mPassword.Length)
{
// 修改字符
mPassword = mPassword.Remove(i, 1).Insert(i, currentText[i].ToString());
}
else
{
// 增加字符
mPassword = mPassword.Insert(i, currentText[i].ToString());
}
}
}
Password = mPassword;
this.ShowText = new string(PasswordChar, mPassword.Length);
if (!string.IsNullOrEmpty(addChar) && start > 0)
{
ShowText = ShowText.Remove(start - 1, 1).Insert(start - 1, addChar);
WaitChange();
}
this.SelectionStart = start;
}
}
/// <summary>
/// 刪除字符
/// </summary>
/// <param name="currentText"></param>
/// <param name="start"></param>
private void RemoveChar(string currentText, int start)
{
if (currentText.Length < mPassword.Length)
{
mPassword = mPassword.Remove(start, mPassword.Length - currentText.Length);
Password = mPassword;
}
}
#endregion
#region Private Methods
/// <summary>
/// 等待明文自動(dòng)隱藏
/// </summary>
private async void WaitChange()
{
try
{
mWaitToken.Cancel();
mWaitToken = new System.Threading.CancellationTokenSource();
await Task.Delay(mDelay, mWaitToken.Token);
mLastStart = this.SelectionStart;
this.ShowText = new string(PasswordChar, mPassword.Length);
this.SelectionStart = mLastStart;
}
catch
{
}
}
#endregion
}
}