Sonhja
Sonhja

Reputation: 8458

How to validate PasswordBox WPF

I'm trying to make a validation for a PasswordBox. For making validations I followed this link, that shows how to validate on TextBox.

The problem comes with PasswordBoxes. Because its Password is not bindable due to security reasons, I tried to make a binding following this link (also explained here, for CodeProject users).

So, apparently, fantastic! I can bind my PasswordBox with its Password property, so then I can bind with my validation. But it ignores me...

This is a regular TextBox that I use and works fine:

<local:ErrorProvider Grid.Column="1" Grid.Row="2" >
    <TextBox Width="160" 
          HorizontalAlignment="Left" 
           Name="textBoxUserPass" 
           Text="{Binding Path=Password, UpdateSourceTrigger=Explicit}" />
 </local:ErrorProvider>

And this is the PasswordBox I tried to simulate:

<local:ErrorProvider Grid.Column="1" Grid.Row="2" >
      <PasswordBox Width="160"
          HorizontalAlignment="Left"
          Name="textBoxUserPass"
          local:PasswordBoxAssistant.BindPassword="True"
          local:PasswordBoxAssistant.BoundPassword="{Binding Path=Password, UpdateSourceTrigger=Explicit}" />
 </local:ErrorProvider>

This is how I get the BindingExpression for each TextBox:

BindingExpression beUserName = textBoxUserName.GetBindingExpression(TextBox.TextProperty);
if (beUserName != null) beUserName.UpdateSource();

And this is how I get it for the PasswordBox:

BindingExpression bePassword = textBoxUserPass.GetBindingExpression(PasswordBoxAssistant.BoundPassword);
if (bePassword != null) bePassword.UpdateSource();

If we made any mistake (defined on my Validation class), when I do this:

if (!beUserName.HasError && !bePassword.HasError)

each BindingExpression should say true of false depending on error validations. But for my PasswordBox never gets the value... Any idea?

Upvotes: 14

Views: 21595

Answers (4)

Simon Mourier
Simon Mourier

Reputation: 139276

Another solution, without using any "unsecure" string in the middle, is to adapt the Window code, something like this:

Let's suppose I have an MVVM object like this, with WPF validation using IDataErrorInfo:

public class MyObject : INotifyPropertyChanged, IDataErrorInfo
{
    ...
    public SecureString SecurePassword
    {
        get
        { ... }
        set
        {
            ...
            OnPropertyChanged("SecurePassword");
        }
    }

    ...

    string IDataErrorInfo.Error { get { return Validate(null); } }
    string IDataErrorInfo.this[string columnName] { get { return Validate(columnName); } }

    private string Validate(string memberName)
    {
        string error = null;
        ...
        if (memberName == "SecurePassword" || memberName == null)
        {
            // this is where I code my custom business rule
            if (SecurePassword == null || SecurePassword.Length == 0)
            {
                error = "Password must be specified.";
            }
        }
        ...
        return error;
    }

}

And a Window Xaml with a PasswordBox like this:

<PasswordBox Name="MyPassword" PasswordChanged="MyPassword_Changed" ... />

Then, the corresponding Window code like this will trigger PasswordBox binding:

// add a custom DependencyProperty
public static readonly DependencyProperty SecurePasswordProperty =
    DependencyProperty.RegisterAttached("SecurePassword", typeof(SecureString), typeof(MyWindow));

public MyWindow()
{
    InitializeComponent();

    DataContext = myObject; // created somewhere

    // create a binding by code
    Binding passwordBinding = new Binding(SecurePasswordProperty.Name);
    passwordBinding.Source = myObject;
    passwordBinding.ValidatesOnDataErrors = true;
    // you can configure other binding stuff here
    MyPassword.SetBinding(SecurePasswordProperty, passwordBinding);
}

private void MyPassword_Changed(object sender, RoutedEventArgs e)
{
    // this should trigger binding and therefore validation
    ((MyObject)DataContext).SecurePassword = MyPassword.SecurePassword;
}

Upvotes: 2

KevinChuelo
KevinChuelo

Reputation: 31

Set Mode=TwoWay on your binding

local:PasswordBoxAssistant.BoundPassword="{Binding Path=Password,Mode=TwoWay,
UpdateSourceTrigger=Explicit}"

Upvotes: 3

Richard Deeming
Richard Deeming

Reputation: 31248

Try setting ValidatesOnDataErrors=True and ValidatesOnExceptions=True on your binding:

<PasswordBox ...
   local:PasswordBoxAssistant.BoundPassword="{Binding Path=Password,
      UpdateSourceTrigger=Explicit, 
      ValidatesOnDataErrors=True, 
      ValidatesOnExceptions=True}"
/>

Upvotes: 12

Cristian Chereches
Cristian Chereches

Reputation: 505

As far as I remember, the only way to add validation on a PasswordBox is to throw a new ValidationException in the setter of the binding property for SecurePassword. The PasswordBoxAssistant will not help you with this.

Upvotes: 2

Related Questions