PasswordBox with MVVM
Asked Answered
C

5

21

Hi people stackoverflow. I'm working with MVVM, I have ViewModel call UserViewModel with a Property Password. In the View have a control PasswordBox.

<PasswordBox x:Name="txtPassword" Password="{Binding Password}" />

But this xaml don't work. How do you do the binding?? Help please!!

Contiguity answered 8/7, 2009 at 10:20 Comment(2)
Have you made sure that the datacontext of the window is set to the view model. You need to post some more code so we can understand your problem.Driving
DataContext it's ok. other properties work fine, but with PasswordBox I can't.Contiguity
S
13

For security reasons the Password property is not a dependency property and therefore you can't bind to it. Unfortunately you'll need to perform the binding in the code behind the old fashioned way (register for OnPropertyChanged event and update the value through code...)


I quick search brings me to this blog post which shows how to write an attached property to sidestep the issue. Whether this is worth doing or not though really depends on your aversion to code-behind.

Sebrinasebum answered 8/7, 2009 at 10:24 Comment(0)
W
4

You can always write a control that wraps the Password and adds a dependency property for the Password property.

I would just use code behind, but if you must you can do something like:

public class BindablePasswordBox : Decorator
{
    public static readonly DependencyProperty PasswordProperty =
        DependencyProperty.Register("Password", typeof(string), typeof(BindablePasswordBox));

    public string Password
    {
        get { return (string)GetValue(PasswordProperty); }
        set { SetValue(PasswordProperty, value); }
    }

    public BindablePasswordBox()
    {
        Child = new PasswordBox();
        ((PasswordBox)Child).PasswordChanged += BindablePasswordBox_PasswordChanged;
    }

    void BindablePasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
    {
        Password = ((PasswordBox)Child).Password;
    }

}
Wideopen answered 8/7, 2009 at 10:50 Comment(2)
I use a similar solution but I find it useful to to register the DependencyProperty with FrameworkPropertyMetadata.BindsTwoWayByDefault so you don't have to declare it in the XAML each time.Elora
I understand this is quite old however if I use this method it removes the ability to set the FontSize and ContentAlignment. How do I get around this?Vanya
T
4

There is an issue with the BindablePasswordBox. It only works in one direction, PasswordBox to PasswordProperty. Below is a modified version of it that works in both directions. It registers a PropertyChangedCallback and updates the PasswordBox's Password when it is called. I hope that someone finds this useful.

public class BindablePasswordBox : Decorator
{
    public static readonly DependencyProperty PasswordProperty = DependencyProperty.Register("Password", typeof(string), typeof(BindablePasswordBox), new PropertyMetadata(string.Empty, OnDependencyPropertyChanged));
    public string Password
    {
        get { return (string)GetValue(PasswordProperty); }
        set { SetValue(PasswordProperty, value); }
    }

    private static void OnDependencyPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
    {
        BindablePasswordBox p = source as BindablePasswordBox;
        if (p != null)
        {
            if (e.Property == PasswordProperty)
            {
                var pb = p.Child as PasswordBox;
                if (pb != null)
                {
                    if (pb.Password != p.Password)
                        pb.Password = p.Password;
                }
            }
        }
    }

    public BindablePasswordBox()
    {
        Child = new PasswordBox();
        ((PasswordBox)Child).PasswordChanged += BindablePasswordBox_PasswordChanged;
    }

    void BindablePasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
    {
        Password = ((PasswordBox)Child).Password;
    }
}
Traumatism answered 24/1, 2014 at 14:35 Comment(0)
D
1

To avoid having the password available in memory as plain text at any point, I provide the value as a parameter to my command.

<Label>User Name</Label>
<TextBox Text="{Binding UserName}" />
<Label>Password</Label>
<PasswordBox Name="PasswordBox" />
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0 16 0 0">
    <Button Margin="0 0 8 0" MinWidth="65" 
            Command="{Binding LoginAccept}" 
            CommandParameter="{Binding ElementName=PasswordBox}">
        Login
    </Button>
    <Button MinWidth="65" Command="{Binding LoginCancel}">Cancel</Button>
</StackPanel>

Then in my view model.

public DelegateCommand<object> LoginAccept { get; private set; }
public DelegateCommand<object> LoginCancel { get; private set; }

public LoginViewModel {
    LoginAccept = new DelegateCommand<object>(o => OnLogin(o), (o) => IsLoginVisible);
    LoginCancel = new DelegateCommand<object>(o => OnLoginCancel(), (o) => IsLoginVisible);
}

private void OnLogin(object o)
{
    var passwordBox = (o as System.Windows.Controls.PasswordBox);
    var password = passwordBox.SecurePassword.Copy();
    passwordBox.Clear();
    ShowLogin = false;
    var credential = new System.Net.NetworkCredential(UserName, password);
}

private void OnLoginCancel()
{
    ShowLogin = false;
}

While it would make sense to provide the SecurePassword directly from the binding, it always seems to provide an empty value. So this does NOT work:

    <Button Margin="0 0 8 0" MinWidth="65" 
            Command="{Binding LoginAccept}" 
            CommandParameter="{Binding ElementName=PasswordBox, Path=SecurePassword}">
Debora answered 7/3, 2016 at 16:12 Comment(4)
I have experienced the exact same thing! do you know why 'SecurePassword directly from the binding' is not working?Hedva
I have no idea besides there being an intentional restriction for that specific type. SecurePassword is not a DependencyProperty which likely contributes to the problem but is a standard readonly property. But one would think you could still pass it as a parameter if nothing else rather than passing the entire control.Debora
Handling controls in the view model is a clear violation of the MVVM pattern.Doss
Yes, it violates the MVVM pattern. Bugs in frameworks sometimes require breaking patterns. In this case, security wins in my industry, and it is preferred to keep passwords encrypted in memory. Patterns are to have code that is easily understood even when changing language and frameworks. In my opinion, the bindings and usage are both clear.Debora
U
0

Check another thread on password box. Its better not to keep the password on any DP or public property.

Other thread on passwordbox

Urbina answered 13/8, 2013 at 6:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.