I have come across a problem with binding to a PasswordBox. It seems it\'s a security risk but I am using the MVVM pattern so I wish to bypass this. I found som
SecureString to the view model using an Attached Behavior and ICommandThere is nothing wrong with code-behind when implementing MVVM. MVVM is an architectural pattern that aims to separate the view from the model/business logic. MVVM describes how to achieve this goal in a reproducible way (the pattern). It doesn't care about implementation details, like how do you structure or implement the view. It just draws the boundaries and defines what is the view, the view model and what the model in terms of this pattern's terminology.
MVVM doesn't care about the language (XAML or C#) or compiler (partial classes). Being language independent is a mandatory characteristic of a design pattern - it must be language neutral.
However, code-behind has some draw backs like making your UI logic harder to understand, when it is wildly distributed between XAML and C#. But most important implementing UI logic or objects like templates, styles, triggers, animations etc in C# is very complex and ugly/less readable than using XAML. XAML is a markup language that uses tags and nesting to visualize object hierarchy. Creating UI using XAML is very convenient. Although there are situations where you are fine choosing to implement UI logic in C# (or code-behind). Handling the PasswordBox is one example.
For this reasons handling the PasswordBox in the code-behind by handling the PasswordBox.PasswordChanged, is no violation of the MVVM pattern.
A clear violation would be to pass a control (the PasswordBox) to the view model. Many solutions recommend this e.g., bay passing the instance of the PasswordBox as ICommand.CommandParameter to the view model. Obviously a very bad and unnecessary recommendation.
If you don't care about using C#, but just want to keep your code-behind file clean or simply want to encapsulate a behavior/UI logic, you can always make use of attached properties and implement an attached behavior.
Opposed of the infamous wide spread helper that enables binding to the plain text password (really bad anti-pattern and security risk), this behavior uses an ICommand to send the password as SecureString to the view model, whenever the PasswordBox raises the PasswordBox.PasswordChanged event.
MainWindow.xaml
ViewModel.cs
public class ViewModel : INotifyPropertyChanged
{
public ICommand VerifyPasswordCommand => new RelayCommand(VerifyPassword);
public void VerifyPassword(object commadParameter)
{
if (commandParameter is SecureString secureString)
{
IntPtr valuePtr = IntPtr.Zero;
try
{
valuePtr = Marshal.SecureStringToGlobalAllocUnicode(value);
string plainTextPassword = Marshal.PtrToStringUni(valuePtr);
// Handle plain text password.
// It's recommended to convert the SecureString to plain text in the model, when really needed.
}
finally
{
Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
}
}
}
}
PasswordBox.cs
// Attached behavior
class PasswordBox : DependencyObject
{
#region Command attached property
public static readonly DependencyProperty CommandProperty =
DependencyProperty.RegisterAttached(
"Command",
typeof(ICommand),
typeof(PasswordBox),
new PropertyMetadata(default(ICommand), PasswordBox.OnSendPasswordCommandChanged));
public static void SetCommand(DependencyObject attachingElement, ICommand value) =>
attachingElement.SetValue(PasswordBox.CommandProperty, value);
public static ICommand GetCommand(DependencyObject attachingElement) =>
(ICommand) attachingElement.GetValue(PasswordBox.CommandProperty);
#endregion
private static void OnSendPasswordCommandChanged(
DependencyObject attachingElement,
DependencyPropertyChangedEventArgs e)
{
if (!(attachingElement is System.Windows.Controls.PasswordBox passwordBox))
{
throw new ArgumentException("Attaching element must be of type 'PasswordBox'");
}
if (e.OldValue != null)
{
return;
}
WeakEventManager