One of WPF's most common pain points is that the PasswordBox control's Password property is not a DependencyProperty — meaning you can't data-bind it in XAML the usual way. This is by design for security reasons, but it creates friction when working with MVVM.
The cleanest solution is to wrap PasswordBox in a custom UserControl that exposes a proper bindable dependency property.
Why PasswordBox.Password Isn't Bindable
Microsoft intentionally made Password a regular CLR property (not a DependencyProperty) to prevent the password value from lingering in memory through the WPF property system, reducing the attack surface for memory inspection. This means you cannot use {Binding} on it directly.
The XAML — BindablePasswordBox UserControl
<UserControl x:Class="YourApp.Components.BindablePasswordBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="30" d:DesignWidth="200">
<PasswordBox x:Name="passwordBox" PasswordChanged="PasswordBox_PasswordChanged" />
</UserControl>
The Code-Behind — C# Implementation
public partial class BindablePasswordBox : UserControl
{
private bool _isPasswordChanging = false;
public string Password
{
get { return (string)GetValue(PasswordProperty); }
set { SetValue(PasswordProperty, value); }
}
public static readonly DependencyProperty PasswordProperty =
DependencyProperty.Register(
"Password",
typeof(string),
typeof(BindablePasswordBox),
new FrameworkPropertyMetadata(
string.Empty,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
PasswordPropertyChanged,
null,
false,
UpdateSourceTrigger.PropertyChanged));
private static void PasswordPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is BindablePasswordBox passwordBox)
{
passwordBox.UpdatePassword();
}
}
private void UpdatePassword()
{
if (!_isPasswordChanging)
{
passwordBox.Password = Password;
}
}
private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
_isPasswordChanging = true;
Password = passwordBox.Password;
_isPasswordChanging = false;
}
}
Usage in XAML (MVVM Binding)
Once the control is created, you can use it just like any other bindable control:
<local:BindablePasswordBox Password="{Binding UserPassword, Mode=TwoWay}" />
ViewModel
public class LoginViewModel : INotifyPropertyChanged
{
private string _userPassword;
public string UserPassword
{
get => _userPassword;
set { _userPassword = value; OnPropertyChanged(); }
}
public ICommand LoginCommand => new RelayCommand(_ => DoLogin());
private void DoLogin()
{
// Use _userPassword here
}
}
Summary
The BindablePasswordBox pattern is the standard MVVM-friendly approach to password binding in WPF. The _isPasswordChanging flag prevents infinite loops when the property is updated from both directions. This pattern is clean, reusable, and fully compatible with data binding and commands.