Access PasswordBox in MVVM environment
For the first time after reading the famous article by Josh Smith WPF Apps With The Model-View-ViewModel Design Pattern, I was very inspired by the MVVM philosophy and decided to write all future projects exclusively using it. As I “introduced” MVVM, I encountered certain difficulties and shortcomings (in my subjective opinion). In one of the projects, I needed a UserControl that would allow me to log in to the web service. When I tried to bind the ViewModel property to the PasswordBox control, I received the following error:
A 'Binding' cannot be set on the 'Password' property of type 'PasswordBox'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject
The reason the Password property is not done DependencyProperty is due to security concerns. If it were possible to bind the property to PasswordBox, then it would be stored in memory in the clear, and this is not a good idea from the point of view of Microsoft. Therefore, the password in PasswordBox is encrypted and decrypted when the Password property is called.
I have found several solutions to this problem. There are ways that preserve the principles of MVVM, but create the problem described above. If the requirements do not provide for this kind of security, then you cango against the system using Attached Properties to still bind the ViewModel property. I will describe another way, which, perhaps, slightly violates the principles of MVVM, but preserves the principle of security of password storage.
Create a simple controller:
To get the password, we need an interface:
We inherit the control from this interface and return the password value in the function:
An unpleasant feature of the method is that LoginControl will have to be created in the code, because You need to get IPasswordSupplier. Using the IoC container, register the instance of the control in App.xaml.cs:
Now in the ViewModel of control we can access the Password property of the PasswordBox:
Thus, the Password property of our ViewModel does not store the value of the password, but receives it each time it is accessed from the PasswordBox, which in turn will decrypt it for us. Perhaps this violates MVVM, as Now our ViewModel is indirectly associated with View through this interface, but still this way seems to me the most suitable for solving the problem.
A 'Binding' cannot be set on the 'Password' property of type 'PasswordBox'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject
The reason the Password property is not done DependencyProperty is due to security concerns. If it were possible to bind the property to PasswordBox, then it would be stored in memory in the clear, and this is not a good idea from the point of view of Microsoft. Therefore, the password in PasswordBox is encrypted and decrypted when the Password property is called.
I have found several solutions to this problem. There are ways that preserve the principles of MVVM, but create the problem described above. If the requirements do not provide for this kind of security, then you can
Create a simple controller:
To get the password, we need an interface:
public interface IPasswordSupplier
{
string GetPassword();
}
We inherit the control from this interface and return the password value in the function:
public partial class LoginControl : UserControl, IPasswordSupplier
{
public LoginControl()
{
InitializeComponent();
}
public string GetPassword()
{
return pwdBox.Password;
}
}
An unpleasant feature of the method is that LoginControl will have to be created in the code, because You need to get IPasswordSupplier. Using the IoC container, register the instance of the control in App.xaml.cs:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
IUnityContainer container = new UnityContainer();
LoginControl loginControl = new LoginControl();
container.RegisterInstance(loginControl);
LoginViewModel loginViewModel = new LoginViewModel(container);
loginControl.DataContext = loginViewModel;
MainWindow mainWindow = new MainWindow(loginControl);
MainWindowViewModel windowViewModel = new MainWindowViewModel(loginViewModel);
mainWindow.DataContext = windowViewModel;
mainWindow.Show();
}
Now in the ViewModel of control we can access the Password property of the PasswordBox:
public string Password
{
get
{
IPasswordSupplier passwordSupplier = container.Resolve();
return passwordSupplier.GetPassword();
}
}
Thus, the Password property of our ViewModel does not store the value of the password, but receives it each time it is accessed from the PasswordBox, which in turn will decrypt it for us. Perhaps this violates MVVM, as Now our ViewModel is indirectly associated with View through this interface, but still this way seems to me the most suitable for solving the problem.