2

I want to have a PasswordBox and another PasswordBox to repeat the chosen password and a submit button.

This is what i got:

WPF:

<UserControl.Resources>
    <converter:PasswordConverter x:Key="PasswdConv"/>
</UserControl.Resources>


<PasswordBox PasswordChar="*" Name="pb1"/>
<PasswordBox PasswordChar="*" Name="pb2"/>
<Button Content="Submit" Command="{Binding ChangePassword}">
    <Button.CommandParameter>
        <MultiBinding Converter="{StaticResource PasswdConv}">
            <MultiBinding.Bindings>
                <Binding ElementName="pb1"/>
                <Binding ElementName="pb2"/>
            </MultiBinding.Bindings>
        </MultiBinding>
    </Button.CommandParameter>
</Button>

Converter:

public class PasswordConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        List<string> s = values.ToList().ConvertAll(p => SHA512(((PasswordBox)p).Password));
        if (s[0] == s[1])
            return s[0];
        return "|NOMATCH|";
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Command(ChangePassword):

if ((p as string) != "|NOMATCH|")
{
    MessageBox.Show("Password changed");
}
else
{
    MessageBox.Show("Passwords not matching");
}

When I set a breakpoint in the converter and in the command I get the following result: As soon as the view loads it jumps into the converter and tries to convert two PasswordBoxes. Both are empty. When I press the Button(It doesn't matter what's in the two PasswordBoxes) it doesn't get into the converter and stops at the command-if. P represents an empty password.

JaFu0815
  • 75
  • 1
  • 6

2 Answers2

2

The Convert method will only be called when a source property of the multi binding changes, but you are binding to the PasswordBox itself and it never changes.

And binding to the Password property won't work either as the PasswordoBox raises no change notification when this property changes.

It does raise a PasswordChanged event though, so you could handle this and set the CommandParameter property in this event handler instead of using a converter:

private void OnPasswordChanged(object sender, RoutedEventArgs e)
{
    string password = "|NOMATCH|";
    List<PasswordBox> pb = new List<PasswordBox>(2) { };
    List<string> s = new List<string>[2] { SHA512(pb1.Password), SHA512(pb2.Password) };
    if (s[0] == s[1])
        password = s[0];

    btn.CommandParameter = password;
}

XAML:

<PasswordBox PasswordChar="*" Name="pb1" PasswordChanged="OnPasswordChanged"/>
<PasswordBox PasswordChar="*" Name="pb2" PasswordChanged="OnPasswordChanged"/>
<Button x:Name="btn" Content="Submit" Command="{Binding ChangePassword}" />

If you want to be able to reuse this functionality across several views and PasswordBox controls, you should write an attached behaviour.

mm8
  • 163,881
  • 10
  • 57
  • 88
0

There are multiple wrong things to consider in your code:

  • Your binding is directly onto control element (in your case the PasswordBox), you should always bind on a (dep) property of it using the "Path" attribute, if you want that the binding is applied more than once for value observation (Why should the framework otherwise fire an PropertyChanged event? Your control doesn't change, but their properties may change )
  • If you use TextBox instead of PasswordBox and add Path="Text" to your Bindings, you get the behavior what you expected
  • Bad news: You can not bind to Password property of a PasswordBox due to security reasons.
A.B.
  • 2,374
  • 3
  • 24
  • 40