0

I searched for a MVVM solution of Setting and Retrieving Password String from PasswordBox. The solutuion I found using Behavior class from System.Windows.Interactivity. Here is the code: View:

<PasswordBox Name="pass" >
        <i:Interaction.Behaviors>
            <vm:PasswordBehavior Password="{Binding Password, Mode=TwoWay}" />
        </i:Interaction.Behaviors>
    </PasswordBox>

And here is the ViewModel:

public class PasswordBehavior : Behavior<PasswordBox>
{
    public static readonly DependencyProperty PasswordProperty =
        DependencyProperty.Register("Password", typeof(string), typeof(PasswordBehavior), new PropertyMetadata(default(string)));

    private bool _skipUpdate;

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

    protected override void OnAttached()    
    {
        AssociatedObject.PasswordChanged += PasswordBox_PasswordChanged;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.PasswordChanged -= PasswordBox_PasswordChanged;
    }

    protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
    {
        base.OnPropertyChanged(e);

        if (e.Property == PasswordProperty)
        {
            if (!_skipUpdate)
            {
                _skipUpdate = true;
                AssociatedObject.Password = e.NewValue as string;
                _skipUpdate = false;
            }
        }
    }

    private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
    {
        _skipUpdate = true;
        Password = AssociatedObject.Password;
        _skipUpdate = false;
    }
}

And it is works! I can see the password in VM, but here is another problem: now I have in VM two separated classes: one from code above and second Class MainLoginFormViewModel : BaseViewModel which contains all other properties, like user name, and commands for check connection, etc.

namespace MyApp.ViewModels
{
public class PasswordBehavior : Behavior<PasswordBox>
{
    ...
}
class MainLoginFormViewModel : BaseViewModel
{
    public MainWindowViewModel()
    {
        sStatus = "Hello";
        GetLoginData();
    }

    private string _sStatus;
    public string sStatus
    {
        get { return _sStatus; }
        set { _sStatus = value; NotifyPropertyChanged("sStatus"); }
    }

    private string _sServer;
    public string sServer
    {
        get { return _sServer; }
        set { _sServer = value; NotifyPropertyChanged("sServer"); }
    }
    private string _sName;
    public string sName
    {
        get { return _sName; }
        set { _sName = value; NotifyPropertyChanged("sName"); }
    }

//...
}
}

I cant mix those two clases, cause one of them is nested from BaseViewModel, which need to implement INotifyPropertyChanged, and second one nested from Behavior, which I need too.

How can I get Password value from class PasswordBehavior into Main MainLoginFormViewModel with authorization logic? It seemed like I missed smth, but I cant understand what....

P.S. I know that there is another way to solve problem with PasswordBox in MVVM, like pass the whole passwordbox control into viewmodel, but in that way I cant SET password from VM (make app "remember" last password on app launch)

Bruce
  • 3
  • 2
  • The behaviors are view-only things, you don't want to have them in vm. But inside behavior you *can* access vm, typically obtained as a `DataContext` of associated object, then cast to some interface (vm should implement it) and if cast is successful - invoking a member of it. `PasswordBox` is special, if you don't want to screw at security, the best would be never *hold* string, rather pass instance of it into vm. Yes, it's not usual, but with password box it's fine. – Sinatr Jan 02 '19 at 13:11
  • Really! I moved class PasswordBehavior into view codebehind and create Property Password in VM and all works as expected. – Bruce Jan 02 '19 at 13:25
  • About security problem. I agree with you, but after discussion with customer I found this: no one care. This will be inner network with no direct connection to network, the customer said - that it is not my problem if someone try to get passes from memory. Just needed that users can easily get access to app on their PCs and nobody can read password from screen. – Bruce Jan 02 '19 at 13:28
  • Possible duplicate of [How to bind to a PasswordBox in MVVM](https://stackoverflow.com/questions/1483892/how-to-bind-to-a-passwordbox-in-mvvm) – Sinatr Jan 02 '19 at 15:04

1 Answers1

0

Just moved class PasswordBehavior into view code behind and create Property "Password" in VM:

    private string _Password;
    public string Password
    {
        get { return _Password; }
        set { _Password = value; NotifyPropertyChanged("Password"); }
    }

All works as expected.

Bruce
  • 3
  • 2