Those who've been following my blog and conversations with the WPF Disciples know that I love the databinding power of WPF, and in almost all cases, I'm a very happy bunny. There is one stain in the awe inspiring goodness that is bound applications, and that’s the PasswordBox
. Superficially, this control looks like a textbox
, but there is a problem when you write MVVM applications and rely on binding the way I do; you can't bind to it. Yes, you heard it right, you can't bind with a PasswordBox
.
There’s a good reason for this lack of binding – PasswordBox.Password
is not a Dependency Property, ostensibly because this would result in the password being stored in clear text in memory, which is a potential security concern. If, however, you aren't too worried about this potential security breach, there is a workaround. Good news, folks – the following class (taken from my forthcoming Twitter client Songbird
) is a way to perform binding with the PasswordBox
.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
namespace SongBird.Infrastructure
{
public class BoundPasswordBox
{
#region BoundPassword
private static bool _updating = false;
public static readonly DependencyProperty BoundPasswordProperty =
DependencyProperty.RegisterAttached("BoundPassword",
typeof(string),
typeof(BoundPasswordBox),
new FrameworkPropertyMetadata(string.Empty, OnBoundPasswordChanged));
public static string GetBoundPassword(DependencyObject d)
{
return (string)d.GetValue(BoundPasswordProperty);
}
public static void SetBoundPassword(DependencyObject d, string value)
{
d.SetValue(BoundPasswordProperty, value);
}
private static void OnBoundPasswordChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
PasswordBox password = d as PasswordBox;
if (password != null)
{
password.PasswordChanged -= PasswordChanged;
}
if (e.NewValue != null)
{
if (!_updating)
{
password.Password = e.NewValue.ToString();
}
}
else
{
password.Password = string.Empty;
}
password.PasswordChanged += new RoutedEventHandler(PasswordChanged);
}
static void PasswordChanged(object sender, RoutedEventArgs e)
{
PasswordBox password = sender as PasswordBox;
_updating = true;
SetBoundPassword(password, password.Password);
_updating = false;
}
#endregion
}
}
Using it couldn't be simpler, just add a reference to the namespace
in your XAML, and update your PasswordBox
with the BoundPasswordBox
class. You've now got a bindable PasswordBox
.
<PasswordBox
Grid.Column="1"
Grid.Row="2"
Margin="5,5,5,5"
password:BoundPasswordBox.BoundPassword="{Binding Path=Password,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
VerticalAlignment="Center"/>