public
Last active

WPF - Bindable PasswordBox

  • Download Gist
WPF - Bindable PasswordBox
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
using System.Windows;
using System.Windows.Controls;
 
namespace CustomControl
{
public class BindablePasswordBox : Decorator
{
/// <summary>
/// The password dependency property.
/// </summary>
public static readonly DependencyProperty PasswordProperty;
 
private bool isPreventCallback;
private RoutedEventHandler savedCallback;
 
/// <summary>
/// Static constructor to initialize the dependency properties.
/// </summary>
static BindablePasswordBox()
{
PasswordProperty = DependencyProperty.Register(
"Password",
typeof(string),
typeof(BindablePasswordBox),
new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(OnPasswordPropertyChanged))
);
}
 
/// <summary>
/// Saves the password changed callback and sets the child element to the password box.
/// </summary>
public BindablePasswordBox()
{
savedCallback = HandlePasswordChanged;
 
PasswordBox passwordBox = new PasswordBox();
passwordBox.PasswordChanged += savedCallback;
Child = passwordBox;
}
 
/// <summary>
/// The password dependency property.
/// </summary>
public string Password
{
get { return GetValue(PasswordProperty) as string; }
set { SetValue(PasswordProperty, value); }
}
 
/// <summary>
/// Handles changes to the password dependency property.
/// </summary>
/// <param name="d">the dependency object</param>
/// <param name="eventArgs">the event args</param>
private static void OnPasswordPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs eventArgs)
{
BindablePasswordBox bindablePasswordBox = (BindablePasswordBox) d;
PasswordBox passwordBox = (PasswordBox) bindablePasswordBox.Child;
 
if (bindablePasswordBox.isPreventCallback)
{
return;
}
 
passwordBox.PasswordChanged -= bindablePasswordBox.savedCallback;
passwordBox.Password = (eventArgs.NewValue != null) ? eventArgs.NewValue.ToString() : "";
passwordBox.PasswordChanged += bindablePasswordBox.savedCallback;
}
 
/// <summary>
/// Handles the password changed event.
/// </summary>
/// <param name="sender">the sender</param>
/// <param name="eventArgs">the event args</param>
private void HandlePasswordChanged(object sender, RoutedEventArgs eventArgs)
{
PasswordBox passwordBox = (PasswordBox) sender;
 
isPreventCallback = true;
Password = passwordBox.Password;
isPreventCallback = false;
}
}
}

This is a workaround for the fact that the Password property of System.Windows.Controls.PasswordBox is not a DependencyProperty. This creates a new BindablePasswordBox using System.Windows.Controls.Decorator.

How do I expose the "Padding" property of the underlying PasswordBox?

I tried to add a new DependencyProperty "PaddingProperty":

public static readonly DependencyProperty PaddingProperty = DependencyProperty.Register(
    "Padding", typeof(double), typeof(BindablePasswordBox),
    new FrameworkPropertyMetadata(new Thickness(2), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(OnPaddingPropertyChanged))
);

public Thickness Padding
{
    get { return (Thickness)GetValue(PaddingProperty); }
    set { SetValue(PaddingProperty, value); }
}

but I cannot set it in XAML, says something about type mismatch.

Is there an attribute I can add to the Padding property so WPF will accept my values in xaml?

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.