Phone/Tablet WPF 应用程序的样式密码框

Phone/Tablet Style password box for WPF application

有什么方法可以使 WPF 应用程序中的 PasswordBox 像大多数 phone 或平板电脑应用程序中使用的那样工作。也就是说,让它短时间显示明文输入的最后一个字符。

没有内置方法可以执行此操作,因为它违反了安全准则。请参阅此 post 以了解有关不推荐这样做的原因的更多信息: How to bind to a PasswordBox in MVVM

这是被接受的答案:

People should have the following security guideline tattooed on the inside of their eyelids: Never keep plain text passwords in memory.

The reason the WPF/Silverlight PasswordBox doesn't expose a DP for the Password property is security related. If WPF/Silverlight were to keep a DP for Password it would require the framework to keep the password itself unencrypted in memory. Which is considered quite a troublesome security attack vector. The PasswordBox uses encrypted memory (of sorts) and the only way to access the password is through the CLR property.

如果您仍想实现此目的,我可以使用 TextBox 控件实现。

XAML:

 <TextBox Name="tbPassword"/>

代码隐藏:

  string actualPassword = "";
  string displayedPassword = "";
  DispatcherTimer dispatcherTimer = new DispatcherTimer();

  public MainWindow()
  {
     InitializeComponent();
     tbPassword.PreviewKeyDown += tbPassword_PreviewKeyDown;
     tbPassword.PreviewTextInput += tbPassword_PreviewTextInput;

     dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
     dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
  }

  private void tbPassword_PreviewKeyDown(object sender, KeyEventArgs e)
  {
     if (e.Key == Key.Back)
     {
        if (actualPassword.Length > 0)
        {
           actualPassword = actualPassword.Substring(0, actualPassword.Length - 1);
           if (actualPassword.Length > 0)
           {
              ShowLastCharacter();
              tbPassword.CaretIndex = displayedPassword.Length;
           }
        }
     }
  }

  private void tbPassword_PreviewTextInput(object sender, TextCompositionEventArgs e)
  {
     actualPassword += e.Text;
     e.Handled = true;
     ShowLastCharacter();
     tbPassword.CaretIndex = displayedPassword.Length;
  }


  private void ShowLastCharacter()
  {
     var lastChar = actualPassword.Substring(actualPassword.Length - 1);
     displayedPassword = "";
     for (int i = 0; i < actualPassword.Length - 1; i++)
        displayedPassword += "•";
     displayedPassword += lastChar;
     tbPassword.Text = displayedPassword;

     if (dispatcherTimer.IsEnabled)
        dispatcherTimer.Stop();

     dispatcherTimer.Start();
  }

  private void dispatcherTimer_Tick(object sender, EventArgs e)
  {
     displayedPassword = "";
     for (int i = 0; i < actualPassword.Length; i++)
        displayedPassword += "•";

     tbPassword.Text = displayedPassword;
     tbPassword.CaretIndex = displayedPassword.Length;
  }