The following solution uses a TextBox
to show the password in plain text and a PasswordBox
to mask the password. The PasswordBox
is on top of the TextBox
, so at first you'd see the password masked. When the "show password" checkbox is checked, the PasswordBox
is hidden, thereby showing the TextBox
beneath (and the password in plain text). Here's the XAML:
<Window.Resources>
<BooleanToVisibilityConverter x:Key="VisibilityConverter" />
</Window.Resources>
<StackPanel>
<Grid>
<TextBox
Text="{Binding Password, UpdateSourceTrigger=PropertyChanged}"
/>
<PasswordBox
x:Name="PasswordBox"
PasswordChanged="OnPasswordChanged"
Visibility="{Binding HidePassword, Converter={StaticResource VisibilityConverter}}"
/>
</Grid>
<CheckBox
Content="Show password"
IsChecked="{Binding ShowPassword}"
/>
</StackPanel>
It doesn't use MVVM for everything (notice the OnPasswordChanged
event handler). This is because the PasswordBox
can't use binding, so the password must be set in the code-behind. But before showing that, here's the view model:
public class ViewModel : ViewModelBase
{
private string _password;
public string Password
{
get => _password;
set => Set(ref _password, value);
}
private bool _showPassword;
public bool ShowPassword
{
get => _showPassword;
set
{
Set(ref _showPassword, value);
RaisePropertyChanged(nameof(HidePassword));
}
}
public bool HidePassword => !ShowPassword;
}
The Set
methods come from the ViewModelBase
parent class, which is part of the MVVM Light Toolkit. The Set
method simply sets the property's backing field and raises the PropertyChanged
event for that property.
Finally, here's the code behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
InitializeViewModel();
}
public ViewModel ViewModel => DataContext as ViewModel;
private void InitializeViewModel()
{
DataContext = new ViewModel();
ViewModel.PropertyChanged += (sender, args) =>
{
// Update the password box only when it's not visible;
// otherwise, the cursor goes to the beginning on each keystroke
if (!PasswordBox.IsVisible)
{
if (args.PropertyName == nameof(ViewModel.Password))
PasswordBox.Password = ViewModel.Password;
}
};
}
private void OnPasswordChanged(object sender, RoutedEventArgs e)
{
ViewModel.Password = PasswordBox.Password;
}
}
After setting the DataContext
to a new ViewModel
, we listen to changes to the Password
property so that we update it in the PasswordBox
. Notice that we only do this when the PasswordBox
is not visible (otherwise, the cursor is set to the beginning on each keystroke and we end up with the password reversed!)
The event handler simply updates the Password
in the view model whenever it's changed in the PasswordBox
.
The code for the "confirm password" TextBox
and PasswordBox
would be very similar.