[c#] How to bind to a PasswordBox in MVVM

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 some interesting code here (has anyone used this or something similar?)

http://www.wpftutorial.net/PasswordBox.html

It technically looks great, but I am unsure of how to retrieve the password.

I basically have properties in my LoginViewModel for Username and Password. Username is fine and is working as it's a TextBox.

I used the code above as stated and entered this

<PasswordBox ff:PasswordHelper.Attach="True"
    ff:PasswordHelper.Password="{Binding Path=Password}" Width="130"/>

When I had the PasswordBox as a TextBox and Binding Path=Password then the property in my LoginViewModel was updated.

My code is very simple, basically I have a Command for my Button. When I press it CanLogin is called and if it returns true it calls Login.
You can see I check my property for Username here which works great.

In Login I send along to my service a Username and Password, Username contains data from my View but Password is Null|Empty

private DelegateCommand loginCommand;

public string Username { get; set; }
public string Password { get; set; }


public ICommand LoginCommand
{
    get
    {
        if (loginCommand == null)
        {
            loginCommand = new DelegateCommand(
                Login, CanLogin );
        }
        return loginCommand;
    }
}

private bool CanLogin()
{
    return !string.IsNullOrEmpty(Username);
}

private void Login()
{
    bool result = securityService.IsValidLogin(Username, Password);

    if (result) { }
    else { }
}

This is what I am doing

<TextBox Text="{Binding Path=Username, UpdateSourceTrigger=PropertyChanged}"
         MinWidth="180" />

<PasswordBox ff:PasswordHelper.Attach="True" 
             ff:PasswordHelper.Password="{Binding Path=Password}" Width="130"/>

I have my TextBox, this is no problem, but in my ViewModel the Password is empty.

Am I doing something wrong or missing a step?

I put a breakpoint and sure enough the code enter the static helper class but it never updates my Password in my ViewModel.

This question is related to c# wpf mvvm wpf-controls passwords

The answer is


You can use this XAML:

<PasswordBox>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="PasswordChanged">
            <i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=PasswordBox}}" CommandParameter="{Binding ElementName=PasswordBox}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</PasswordBox>

And this command execute method:

private void ExecutePasswordChangedCommand(PasswordBox obj)
{ 
   if (obj != null)
     Password = obj.Password;
}

This requires adding the System.Windows.Interactivity assembly to your project and referencing it via xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity".


Maybe I am missing something, but it seems like most of these solutions overcomplicate things and do away with secure practices.

This method does not violate the MVVM pattern and maintains complete security. Yes, technically it is code behind, but it is nothing more than a "special case" binding. The ViewModel still has no knowledge of the View implementation, which in my mind it does if you are trying to pass the PasswordBox in to the ViewModel.

Code Behind != Automatic MVVM violation. It all depends on what you do with it. In this case, we are just manually coding a binding, so its all considered part of the UI implementation and therefore is ok.

In the ViewModel, just a simple property. I made it "write only" since there shouldn't be a need to retrieve it from outside the ViewModel for any reason, but it doesn't have to be. Note that it is a SecureString, not just a string.

public SecureString SecurePassword { private get; set; }

In the xaml, you set up a PasswordChanged event handler.

<PasswordBox PasswordChanged="PasswordBox_PasswordChanged"/>

In the code behind:

private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
    if (this.DataContext != null)
    { ((dynamic)this.DataContext).SecurePassword = ((PasswordBox)sender).SecurePassword; }
}

With this method, your password remains in a SecureString at all times and therefore provides maximum security. If you really don't care about security or you need the clear text password for a downstream method that requires it (note: most .NET methods that require a password also support a SecureString option, so you may not really need a clear text password even if you think you do), you can just use the Password property instead. Like this:

(ViewModel property)

public string Password { private get; set; }

(Code behind)

private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
    if (this.DataContext != null)
    { ((dynamic)this.DataContext).Password = ((PasswordBox)sender).Password; }
}

If you wanted to keep things strongly typed, you could substitute the (dynamic) cast with the interface of your ViewModel. But really, "normal" data bindings aren't strongly typed either, so its not that big a deal.

private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
    if (this.DataContext != null)
    { ((IMyViewModel)this.DataContext).Password = ((PasswordBox)sender).Password; }
}

So best of all worlds - your password is secure, your ViewModel just has a property like any other property, and your View is self contained with no external references required.


As mentioned before VM should be unaware of the View but passing whole PasswordBox looks like the simplest approach. So maybe instead of casting passed parameter to PasswordBox use Reflection to extract Password property from it. In this case VM expects some kind of Password Container with property Password(I'm ussing RelayCommands from MVMM Light-Toolkit):

public RelayCommand<object> SignIn
{
    get
    {
        if (this.signIn == null)
        {
            this.signIn = new RelayCommand<object>((passwordContainer) => 
                {
                    var password = passwordContainer.GetType().GetProperty("Password").GetValue(passwordContainer) as string;
                    this.authenticationService.Authenticate(this.Login, password);
                });
        }

        return this.signIn;
    }
}

It can be easily tested with anonymous class:

var passwordContainer = new
    {
        Password = "password"
    };

I spent a great deal of time looking at various solutions. I didn't like the decorators idea, behaviors mess up the validation UI, code behind... really?

The best one yet is to stick to a custom attached property and bind to your SecureString property in your view model. Keep it in there for as long as you can. Whenever you'll need quick access to the plain password, temporarily convert it to an unsecure string using the code below:

namespace Namespace.Extensions
{
    using System;
    using System.Runtime.InteropServices;
    using System.Security;

    /// <summary>
    /// Provides unsafe temporary operations on secured strings.
    /// </summary>
    [SuppressUnmanagedCodeSecurity]
    public static class SecureStringExtensions
    {
        /// <summary>
        /// Converts a secured string to an unsecured string.
        /// </summary>
        public static string ToUnsecuredString(this SecureString secureString)
        {
            // copy&paste from the internal System.Net.UnsafeNclNativeMethods
            IntPtr bstrPtr = IntPtr.Zero;
            if (secureString != null)
            {
                if (secureString.Length != 0)
                {
                    try
                    {
                        bstrPtr = Marshal.SecureStringToBSTR(secureString);
                        return Marshal.PtrToStringBSTR(bstrPtr);
                    }
                    finally
                    {
                        if (bstrPtr != IntPtr.Zero)
                            Marshal.ZeroFreeBSTR(bstrPtr);
                    }
                }
            }
            return string.Empty;
        }

        /// <summary>
        /// Copies the existing instance of a secure string into the destination, clearing the destination beforehand.
        /// </summary>
        public static void CopyInto(this SecureString source, SecureString destination)
        {
            destination.Clear();
            foreach (var chr in source.ToUnsecuredString())
            {
                destination.AppendChar(chr);
            }
        }

        /// <summary>
        /// Converts an unsecured string to a secured string.
        /// </summary>
        public static SecureString ToSecuredString(this string plainString)
        {
            if (string.IsNullOrEmpty(plainString))
            {
                return new SecureString();
            }

            SecureString secure = new SecureString();
            foreach (char c in plainString)
            {
                secure.AppendChar(c);
            }
            return secure;
        }
    }
}

Make sure you allow the GC to collect your UI element, so resist the urge of using a static event handler for the PasswordChanged event on the PasswordBox. I also discovered an anomaly where the control wasn't updating the UI when using the SecurePassword property for setting it up, reason why I'm copying the password into Password instead.

namespace Namespace.Controls
{
    using System.Security;
    using System.Windows;
    using System.Windows.Controls;
    using Namespace.Extensions;

    /// <summary>
    /// Creates a bindable attached property for the <see cref="PasswordBox.SecurePassword"/> property.
    /// </summary>
    public static class PasswordBoxHelper
    {
        // an attached behavior won't work due to view model validation not picking up the right control to adorn
        public static readonly DependencyProperty SecurePasswordBindingProperty = DependencyProperty.RegisterAttached(
            "SecurePassword",
            typeof(SecureString),
            typeof(PasswordBoxHelper),
            new FrameworkPropertyMetadata(new SecureString(),FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, AttachedPropertyValueChanged)
        );

        private static readonly DependencyProperty _passwordBindingMarshallerProperty = DependencyProperty.RegisterAttached(
            "PasswordBindingMarshaller",
            typeof(PasswordBindingMarshaller),
            typeof(PasswordBoxHelper),
            new PropertyMetadata()
        );

        public static void SetSecurePassword(PasswordBox element, SecureString secureString)
        {
            element.SetValue(SecurePasswordBindingProperty, secureString);
        }

        public static SecureString GetSecurePassword(PasswordBox element)
        {
            return element.GetValue(SecurePasswordBindingProperty) as SecureString;
        }

        private static void AttachedPropertyValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            // we'll need to hook up to one of the element's events
            // in order to allow the GC to collect the control, we'll wrap the event handler inside an object living in an attached property
            // don't be tempted to use the Unloaded event as that will be fired  even when the control is still alive and well (e.g. switching tabs in a tab control) 
            var passwordBox = (PasswordBox)d;
            var bindingMarshaller = passwordBox.GetValue(_passwordBindingMarshallerProperty) as PasswordBindingMarshaller;
            if (bindingMarshaller == null)
            {
                bindingMarshaller = new PasswordBindingMarshaller(passwordBox);
                passwordBox.SetValue(_passwordBindingMarshallerProperty, bindingMarshaller);
            }

            bindingMarshaller.UpdatePasswordBox(e.NewValue as SecureString);
        }

        /// <summary>
        /// Encapsulated event logic
        /// </summary>
        private class PasswordBindingMarshaller
        {
            private readonly PasswordBox _passwordBox;
            private bool _isMarshalling;

            public PasswordBindingMarshaller(PasswordBox passwordBox)
            {
                _passwordBox = passwordBox;
                _passwordBox.PasswordChanged += this.PasswordBoxPasswordChanged;
            }

            public void UpdatePasswordBox(SecureString newPassword)
            {
                if (_isMarshalling)
                {
                    return;
                }

                _isMarshalling = true;
                try
                {
                    // setting up the SecuredPassword won't trigger a visual update so we'll have to use the Password property
                    _passwordBox.Password = newPassword.ToUnsecuredString();

                    // you may try the statement below, however the benefits are minimal security wise (you still have to extract the unsecured password for copying)
                    //newPassword.CopyInto(_passwordBox.SecurePassword);
                }
                finally
                {
                    _isMarshalling = false;
                }
            }

            private void PasswordBoxPasswordChanged(object sender, RoutedEventArgs e)
            {
                // copy the password into the attached property
                if (_isMarshalling)
                {
                    return;
                }

                _isMarshalling = true;
                try
                {
                    SetSecurePassword(_passwordBox, _passwordBox.SecurePassword.Copy());
                }
                finally
                {
                    _isMarshalling = false;
                }
            }
        }
    }
}

And the XAML usage:

<PasswordBox controls:PasswordBoxHelper.SecurePassword="{Binding LogonPassword, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}">

My property in the view model looked like this:

[RequiredSecureString]
public SecureString LogonPassword
{
   get
   {
       return _logonPassword;
   }
   set
   {
       _logonPassword = value;
       NotifyPropertyChanged(nameof(LogonPassword));
   }
}

The RequiredSecureString is just a simple custom validator that has the following logic:

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]    
public class RequiredSecureStringAttribute:ValidationAttribute
{
    public RequiredSecureStringAttribute()
        :base("Field is required")
    {            
    }

    public override bool IsValid(object value)
    {
        return (value as SecureString)?.Length > 0;
    }
}

Here you have it. A complete and tested pure MVVM solution.


For anyone who is aware of the risks this implementation imposes, to have the password sync to your ViewModel simply add Mode=OneWayToSource.

XAML

<PasswordBox
    ff:PasswordHelper.Attach="True"
    ff:PasswordHelper.Password="{Binding Path=Password, Mode=OneWayToSource}" />

I am using succinct MVVM-friendly solution that hasn't been mentioned yet. First, I name the PasswordBox in XAML:

<PasswordBox x:Name="Password" />

Then I add a single method call into view constructor:

public LoginWindow()
{
    InitializeComponent();
    ExposeControl<LoginViewModel>.Expose(this, view => view.Password,
        (model, box) => model.SetPasswordBox(box));
}

And that's it. View model will receive notification when it is attached to a view via DataContext and another notification when it is detached. The contents of this notification are configurable via the lambdas, but usually it's just a setter or method call on the view model, passing the problematic control as a parameter.

It can be made MVVM-friendly very easily by having the view expose interface instead of child controls.

The above code relies on helper class published on my blog.


Send a SecureString to the view model using an Attached Behavior and ICommand

There 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

<Window>
  <Window.DataContext>
    <ViewModel />
  </Window.DataContext>

  <PasswordBox PasswordBox.Command="{Binding VerifyPasswordCommand}" />
</Window>

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<object, RoutedEventArgs>.AddHandler(
      passwordBox,
      nameof(System.Windows.Controls.PasswordBox.PasswordChanged),
      SendPassword_OnPasswordChanged);
  }

  private static void SendPassword_OnPasswordChanged(object sender, RoutedEventArgs e)
  {
    var attachedElement = sender as System.Windows.Controls.PasswordBox;
    SecureString commandParameter = attachedElement?.SecurePassword;
    if (commandParameter == null || commandParameter.Length < 1)
    {
      return;
    }

    ICommand sendCommand = GetCommand(attachedElement);
    sendCommand?.Execute(commandParameter);
  }
}

If you want it combined it all in only one control and one command

<PasswordBox Name="PasswordBoxPin" PasswordChar="*">
    <PasswordBox.InputBindings>
        <KeyBinding Key="Return" Command="{Binding AuthentifyEmpCommand}" CommandParameter="{Binding ElementName=PasswordBoxPin}"/>
    </PasswordBox.InputBindings>
</PasswordBox>

And on your Vm (like Konamiman showed)

public void AuthentifyEmp(object obj)
{
    var passwordBox = obj as PasswordBox;
    var password = passwordBox.Password;
}
private RelayCommand _authentifyEmpCommand;
public RelayCommand AuthentifyEmpCommand => _authentifyEmpCommand ?? (_authentifyEmpCommand = new RelayCommand(AuthentifyEmp, null));

EDIT: Based on comments I feel the need to specify that this is a violation of MVVM pattern, use it only if that is not one of your primary concerns.


For complete newbies like me, here is a complete working sample of what Konamiman suggested above. Thanks Konamiman.

XAML

    <PasswordBox x:Name="textBoxPassword"/>
    <Button x:Name="buttonLogin" Content="Login"
            Command="{Binding PasswordCommand}"
            CommandParameter="{Binding ElementName=textBoxPassword}"/> 

ViewModel

public class YourViewModel : ViewModelBase
{
    private ICommand _passwordCommand;
    public ICommand PasswordCommand
    {
        get {
            if (_passwordCommand == null) {
                _passwordCommand = new RelayCommand<object>(PasswordClick);
            }
            return _passwordCommand;
        }
    }

    public YourViewModel()
    {
    }

    private void PasswordClick(object p)
    {
        var password = p as PasswordBox;
        Console.WriteLine("Password is: {0}", password.Password);
    }
}

_x000D_
_x000D_
<UserControl x:Class="Elections.Server.Handler.Views.LoginView"_x000D_
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"_x000D_
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"_x000D_
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" _x000D_
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"_x000D_
             xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"_x000D_
             xmlns:cal="http://www.caliburnproject.org"_x000D_
             mc:Ignorable="d" _x000D_
             Height="531" Width="1096">_x000D_
    <ContentControl>_x000D_
        <ContentControl.Background>_x000D_
            <ImageBrush/>_x000D_
        </ContentControl.Background>_x000D_
        <Grid >_x000D_
            <Border BorderBrush="#FFABADB3" BorderThickness="1" HorizontalAlignment="Left" Height="23" Margin="900,100,0,0" VerticalAlignment="Top" Width="160">_x000D_
                <TextBox TextWrapping="Wrap"/>_x000D_
            </Border>_x000D_
            <Border BorderBrush="#FFABADB3" BorderThickness="1" HorizontalAlignment="Left" Height="23" Margin="900,150,0,0" VerticalAlignment="Top" Width="160">_x000D_
                <PasswordBox x:Name="PasswordBox"/>_x000D_
            </Border>_x000D_
            <Button Content="Login" HorizontalAlignment="Left" Margin="985,200,0,0" VerticalAlignment="Top" Width="75">_x000D_
                <i:Interaction.Triggers>_x000D_
                    <i:EventTrigger EventName="Click">_x000D_
                        <cal:ActionMessage MethodName="Login">_x000D_
                            <cal:Parameter Value="{Binding ElementName=PasswordBox}" />_x000D_
                        </cal:ActionMessage>_x000D_
                    </i:EventTrigger>_x000D_
                </i:Interaction.Triggers>_x000D_
            </Button>_x000D_
_x000D_
        </Grid>_x000D_
    </ContentControl>_x000D_
</UserControl>
_x000D_
_x000D_
_x000D_

_x000D_
_x000D_
using System;_x000D_
using System.Windows;_x000D_
using System.Windows.Controls;_x000D_
using Caliburn.Micro;_x000D_
_x000D_
namespace Elections.Server.Handler.ViewModels_x000D_
{_x000D_
    public class LoginViewModel : PropertyChangedBase_x000D_
    {_x000D_
        MainViewModel _mainViewModel;_x000D_
        public void SetMain(MainViewModel mainViewModel)_x000D_
        {_x000D_
            _mainViewModel = mainViewModel;_x000D_
        }_x000D_
_x000D_
        public void Login(Object password)_x000D_
        {_x000D_
            var pass = (PasswordBox) password;_x000D_
            MessageBox.Show(pass.Password);_x000D_
_x000D_
            //_mainViewModel.ScreenView = _mainViewModel.ControlPanelView;_x000D_
            //_mainViewModel.TitleWindow = "Panel de Control";_x000D_
            //HandlerBootstrapper.Title(_mainViewModel.TitleWindow);_x000D_
        }_x000D_
    }_x000D_
}
_x000D_
_x000D_
_x000D_

;) easy!


Here's my take on it:

  1. Using an attached property to bind the password defeats the purpose of securing the password. The Password property of a password box is not bindable for a reason.

  2. Passing the password box as command parameter will make the ViewModel aware of the control. This will not work if you plan to make your ViewModel reusable cross platform. Don't make your VM aware of your View or any other controls.

  3. I don't think introducing a new property, an interface, subscribing to password changed events or any other complicated things is necessary for a simple task of providing the password.

XAML

<PasswordBox x:Name="pbPassword" />
<Button Content="Login" Command="{Binding LoginCommand}" x:Name="btnLogin"/>

Code behind - using code behind does not necessarily violate MVVM. As long as you don't put any business logic in it.

btnLogin.CommandParameter = new Func<string>(()=>pbPassword.Password); 

ViewModel

LoginCommand = new RelayCommand<Func<string>>(getpwd=> { service.Login(username, getpwd()); });

As you can see i am binding to Password, but maybe its bind it to the static class..

It is an attached property. This kind of property can be applied to any kind of DependencyObject, not just the type in which it is declared. So even though it is declared in the PasswordHelper static class, it is applied to the PasswordBox on which you use it.

To use this attached property, you just need to bind it to the Password property in your ViewModel :

<PasswordBox w:PasswordHelper.Attach="True" 
         w:PasswordHelper.Password="{Binding Password}"/>

My 2 cents:

I developed once a typical login dialog (user and password boxes, plus "Ok" button) using WPF and MVVM. I solved the password binding issue by simply passing the PasswordBox control itself as a parameter to the command attached to the "Ok" button. So in the view I had:

<PasswordBox Name="txtPassword" VerticalAlignment="Top" Width="120" />
<Button Content="Ok" Command="{Binding Path=OkCommand}"
   CommandParameter="{Binding ElementName=txtPassword}"/>

And in the ViewModel, the Execute method of the attached command was as follows:

void Execute(object parameter)
{
    var passwordBox = parameter as PasswordBox;
    var password = passwordBox.Password;
    //Now go ahead and check the user name and password
}

This slightly violates the MVVM pattern since now the ViewModel knows something about how the View is implemented, but in that particular project I could afford it. Hope it is useful for someone as well.


you can do it with attached property, see it.. PasswordBox with MVVM


I posted a GIST here that is a bindable password box.

using System.Windows;
using System.Windows.Controls;

namespace CustomControl
{
    public class BindablePasswordBox : Decorator
    {
        /// <summary>
        /// The password dependency property.
        /// </summary>
        public static readonly DependencyProperty PasswordProperty;

        private bool isPreventCallback;
        private RoutedEventHandler savedCallback;

        /// <summary>
        /// Static constructor to initialize the dependency properties.
        /// </summary>
        static BindablePasswordBox()
        {
            PasswordProperty = DependencyProperty.Register(
                "Password",
                typeof(string),
                typeof(BindablePasswordBox),
                new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(OnPasswordPropertyChanged))
            );
        }

        /// <summary>
        /// Saves the password changed callback and sets the child element to the password box.
        /// </summary>
        public BindablePasswordBox()
        {
            savedCallback = HandlePasswordChanged;

            PasswordBox passwordBox = new PasswordBox();
            passwordBox.PasswordChanged += savedCallback;
            Child = passwordBox;
        }

        /// <summary>
        /// The password dependency property.
        /// </summary>
        public string Password
        {
            get { return GetValue(PasswordProperty) as string; }
            set { SetValue(PasswordProperty, value); }
        }

        /// <summary>
        /// Handles changes to the password dependency property.
        /// </summary>
        /// <param name="d">the dependency object</param>
        /// <param name="eventArgs">the event args</param>
        private static void OnPasswordPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs eventArgs)
        {
            BindablePasswordBox bindablePasswordBox = (BindablePasswordBox) d;
            PasswordBox passwordBox = (PasswordBox) bindablePasswordBox.Child;

            if (bindablePasswordBox.isPreventCallback)
            {
                return;
            }

            passwordBox.PasswordChanged -= bindablePasswordBox.savedCallback;
            passwordBox.Password = (eventArgs.NewValue != null) ? eventArgs.NewValue.ToString() : "";
            passwordBox.PasswordChanged += bindablePasswordBox.savedCallback;
        }

        /// <summary>
        /// Handles the password changed event.
        /// </summary>
        /// <param name="sender">the sender</param>
        /// <param name="eventArgs">the event args</param>
        private void HandlePasswordChanged(object sender, RoutedEventArgs eventArgs)
        {
            PasswordBox passwordBox = (PasswordBox) sender;

            isPreventCallback = true;
            Password = passwordBox.Password;
            isPreventCallback = false;
        }
    }
}

This implementation is slightly different. You pass a passwordbox to the View thru binding of a property in ViewModel, it doesn't use any command params. The ViewModel Stays Ignorant of the View. I have a VB vs 2010 Project that can be downloaded from SkyDrive. Wpf MvvM PassWordBox Example.zip https://skydrive.live.com/redir.aspx?cid=e95997d33a9f8d73&resid=E95997D33A9F8D73!511

The way that I am Using PasswordBox in a Wpf MvvM Application is pretty simplistic and works well for Me. That does not mean that I think it is the correct way or the best way. It is just an implementation of Using PasswordBox and the MvvM Pattern.

Basicly You create a public readonly property that the View can bind to as a PasswordBox (The actual control) Example:

Private _thePassWordBox As PasswordBox
Public ReadOnly Property ThePassWordBox As PasswordBox
    Get
        If IsNothing(_thePassWordBox) Then _thePassWordBox = New PasswordBox
        Return _thePassWordBox
    End Get
End Property

I use a backing field just to do the self Initialization of the property.

Then From Xaml you bind the Content of a ContentControl or a Control Container Example:

 <ContentControl Grid.Column="1" Grid.Row="1" Height="23" Width="120" Content="{Binding Path=ThePassWordBox}" HorizontalAlignment="Center" VerticalAlignment="Center" />

From there you have full control of the passwordbox I also use a PasswordAccessor (Just a Function of String) to return the Password Value when doing login or whatever else you want the Password for. In the Example I have a public property in a Generic User Object Model. Example:

Public Property PasswordAccessor() As Func(Of String)

In the User Object the password string property is readonly without any backing store it just returns the Password from the PasswordBox. Example:

Public ReadOnly Property PassWord As String
    Get
        Return If((PasswordAccessor Is Nothing), String.Empty, PasswordAccessor.Invoke())
    End Get
End Property

Then in the ViewModel I make sure that the Accessor is created and set to the PasswordBox.Password property' Example:

Public Sub New()
    'Sets the Accessor for the Password Property
    SetPasswordAccessor(Function() ThePassWordBox.Password)
End Sub

Friend Sub SetPasswordAccessor(ByVal accessor As Func(Of String))
    If Not IsNothing(VMUser) Then VMUser.PasswordAccessor = accessor
End Sub

When I need the Password string say for login I just get the User Objects Password property that really invokes the Function to grab the password and return it, then the actual password is not stored by the User Object. Example: would be in the ViewModel

Private Function LogIn() as Boolean
    'Make call to your Authentication methods and or functions. I usally place that code in the Model
    Return AuthenticationManager.Login(New UserIdentity(User.UserName, User.Password)
End Function

That should Do It. The ViewModel doesn't need any knowledge of the View's Controls. The View Just binds to property in the ViewModel, not any different than the View Binding to an Image or Other Resource. In this case that resource(Property) just happens to be a usercontrol. It allows for testing as the ViewModel creates and owns the Property and the Property is independent of the View. As for Security I don't know how good this implementation is. But by using a Function the Value is not stored in the Property itself just accessed by the Property.


While I agree it's important to avoid storing the password anywhere, I still need the ability to instantiate the view model without a view and execute my tests against it.

The solution that worked for me was to register the PasswordBox.Password function with the view model, and have the view model invoke it when executing the login code.

This does mean a line of code in the view's codebehind.

So, in my Login.xaml I have

<PasswordBox x:Name="PasswordBox"/>

and in Login.xaml.cs I have

LoginViewModel.PasswordHandler = () => PasswordBox.Password;

then in LoginViewModel.cs I have the PasswordHandler defined

public Func<string> PasswordHandler { get; set; }

and when login needs to happen the code invokes the handler to get the password from the view...

bool loginResult = Login(Username, PasswordHandler());

This way, when I want to test the viewmodel I can simply set PasswordHandler to an anonymous method that lets me deliver whatever password I want to use in the test.


To solve the OP problem without breaking the MVVM, I would use custom value converter and a wrapper for the value (the password) that has to be retrieved from the password box.

public interface IWrappedParameter<T>
{
    T Value { get; }
}

public class PasswordBoxWrapper : IWrappedParameter<string>
{
    private readonly PasswordBox _source;

    public string Value
    {
        get { return _source != null ? _source.Password : string.Empty; }
    }

    public PasswordBoxWrapper(PasswordBox source)
    {
        _source = source;
    }
}

public class PasswordBoxConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        // Implement type and value check here...
        return new PasswordBoxWrapper((PasswordBox)value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new InvalidOperationException("No conversion.");
    }
}

In the view model:

public string Username { get; set; }

public ICommand LoginCommand
{
    get
    {
        return new RelayCommand<IWrappedParameter<string>>(password => { Login(Username, password); });
    }
}

private void Login(string username, string password)
{
    // Perform login here...
}

Because the view model uses IWrappedParameter<T>, it does not need to have any knowledge about PasswordBoxWrapper nor PasswordBoxConverter. This way you can isolate the PasswordBox object from the view model and not break the MVVM pattern.

In the view:

<Window.Resources>
    <h:PasswordBoxConverter x:Key="PwdConverter" />
</Window.Resources>
...
<PasswordBox Name="PwdBox" />
<Button Content="Login" Command="{Binding LoginCommand}"
        CommandParameter="{Binding ElementName=PwdBox, Converter={StaticResource PwdConverter}}" />

I spent ages trying to get this working. In the end, I gave up and just used the PasswordBoxEdit from DevExpress.

It is the simplest solution ever, as it allows binding without pulling any horrible tricks.

Solution on DevExpress website

For the record, I am not affiliated with DevExpress in any way.


You find a solution for the PasswordBox in the ViewModel sample application of the WPF Application Framework (WAF) project.

However, Justin is right. Don't pass the password as plain text between View and ViewModel. Use SecureString instead (See MSDN PasswordBox).


well my answerd is more simple just in the for the MVVM pattern

in class viewmodel

public string password;

PasswordChangedCommand = new DelegateCommand<RoutedEventArgs>(PasswordChanged);

Private void PasswordChanged(RoutedEventArgs obj)

{

    var e = (WatermarkPasswordBox)obj.OriginalSource;

    //or depending or what are you using

    var e = (PasswordBox)obj.OriginalSource;

    password =e.Password;

}

the password property of the PasswordBox that win provides or WatermarkPasswordBox that XCeedtoolkit provides generates an RoutedEventArgs so you can bind it.

now in xmal view

<Xceed:WatermarkPasswordBox Watermark="Input your Password" Grid.Column="1" Grid.ColumnSpan="3" Grid.Row="7" PasswordChar="*" >

        <i:Interaction.Triggers>

            <i:EventTrigger EventName="PasswordChanged">

                <prism:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path= DataContext.PasswordChangedCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path= Password}"/>

            </i:EventTrigger>

        </i:Interaction.Triggers>

    </Xceed:WatermarkPasswordBox>

or

<PasswordBox Grid.Column="1" Grid.ColumnSpan="3" Grid.Row="7" PasswordChar="*" >

        <i:Interaction.Triggers>

            <i:EventTrigger EventName="PasswordChanged">

                <prism:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path= DataContext.PasswordChangedCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path= Password}"/>

            </i:EventTrigger>

        </i:Interaction.Triggers>

    </PasswordBox>

I used an authentication check followed by a sub called by a mediator class to the View (which also implements an authentication check) to write the password to the data class.

It's not a perfect solution; however, it remedied my problem of not being able to move the password.


Its very simple . Create another property for password and Bind this with TextBox

But all input operations perform with actual password property

private string _Password;

    public string PasswordChar
    {
        get
        {
            string szChar = "";

            foreach(char szCahr in _Password)
            {
                szChar = szChar + "*";
            }

            return szChar;
        }

        set
        {
            _PasswordChar = value; NotifyPropertyChanged();
        }
    }

public string Password { get { return _Password; }

        set
        {
            _Password = value; NotifyPropertyChanged();
            PasswordChar = _Password;
        }
    }


A simple solution without violating the MVVM pattern is to introduce an event (or delegate) in the ViewModel that harvests the password.

In the ViewModel:

public event EventHandler<HarvestPasswordEventArgs> HarvestPassword;

with these EventArgs:

class HarvestPasswordEventArgs : EventArgs
{
    public string Password;
}

in the View, subscribe to the event on creating the ViewModel and fill in the password value.

_viewModel.HarvestPassword += (sender, args) => 
    args.Password = passwordBox1.Password;

In the ViewModel, when you need the password, you can fire the event and harvest the password from there:

if (HarvestPassword == null)
  //bah 
  return;

var pwargs = new HarvestPasswordEventArgs();
HarvestPassword(this, pwargs);

LoginHelpers.Login(Username, pwargs.Password);

To me, both of these things feel wrong:

  • Implementing clear text password properties
  • Sending the PasswordBox as a command parameter to the ViewModel

Transferring the SecurePassword (SecureString instance) as described by Steve in CO seems acceptable. I prefer Behaviors to code behind, and I also had the additional requirement of being able to reset the password from the viewmodel.

Xaml (Password is the ViewModel property):

<PasswordBox>
    <i:Interaction.Behaviors>
        <behaviors:PasswordBinding BoundPassword="{Binding Password, Mode=TwoWay}" />
    </i:Interaction.Behaviors>
</PasswordBox>

Behavior:

using System.Security;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;

namespace Evidence.OutlookIntegration.AddinLogic.Behaviors
{
    /// <summary>
    /// Intermediate class that handles password box binding (which is not possible directly).
    /// </summary>
    public class PasswordBoxBindingBehavior : Behavior<PasswordBox>
    {
        // BoundPassword
        public SecureString BoundPassword { get { return (SecureString)GetValue(BoundPasswordProperty); } set { SetValue(BoundPasswordProperty, value); } }
        public static readonly DependencyProperty BoundPasswordProperty = DependencyProperty.Register("BoundPassword", typeof(SecureString), typeof(PasswordBoxBindingBehavior), new FrameworkPropertyMetadata(OnBoundPasswordChanged));

        protected override void OnAttached()
        {
            this.AssociatedObject.PasswordChanged += AssociatedObjectOnPasswordChanged;
            base.OnAttached();
        }

        /// <summary>
        /// Link up the intermediate SecureString (BoundPassword) to the UI instance
        /// </summary>
        private void AssociatedObjectOnPasswordChanged(object s, RoutedEventArgs e)
        {
            this.BoundPassword = this.AssociatedObject.SecurePassword;
        }

        /// <summary>
        /// Reacts to password reset on viewmodel (ViewModel.Password = new SecureString())
        /// </summary>
        private static void OnBoundPasswordChanged(object s, DependencyPropertyChangedEventArgs e)
        {
            var box = ((PasswordBoxBindingBehavior)s).AssociatedObject;
            if (box != null)
            {
                if (((SecureString)e.NewValue).Length == 0)
                    box.Password = string.Empty;
            }
        }

    }
}

In windows universal app

you can use this code with the property "Password" and binding with the modelView

_x000D_
_x000D_
 <PasswordBox x:Uid="PasswordBox" Password="{Binding Waiter.Password, Mode=TwoWay}" Name="txtPassword" HorizontalAlignment="Stretch" Margin="50,200,50,0" VerticalAlignment="Top"/>
_x000D_
_x000D_
_x000D_


This works just fine for me.

<Button Command="{Binding Connect}" 
        CommandParameter="{Binding ElementName=MyPasswordBox}"/>

I figured I'd throw my solution in the mix, since this is such a common issue... and having plenty of options is always a good thing.

I simply wrapped a PasswordBox in a UserControl and implemented a DependencyProperty to be able to bind. I'm doing everything I can to avoid storing any clear text in the memory, so everything is done through a SecureString and the PasswordBox.Password property. During the foreach loop, each character does get exposed, but it's very brief. Honestly, if you're worried about your WPF application to be compromised from this brief exposure, you've got bigger security issues that should be handled.

The beauty of this is that you are not breaking any MVVM rules, even the "purist" ones, since this is a UserControl, so it's allowed to have code-behind. When you're using it, you can have pure communication between View and ViewModel without your VideModel being aware of any part of View or the source of the password. Just make sure you're binding to SecureString in your ViewModel.

BindablePasswordBox.xaml

<UserControl x:Class="BK.WPF.CustomControls.BindanblePasswordBox"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" d:DesignHeight="22" d:DesignWidth="150">
    <PasswordBox x:Name="PswdBox"/>
</UserControl>

BindablePasswordBox.xaml.cs (Version 1 - No two-way binding support.)

using System.ComponentModel;
using System.Security;
using System.Windows;
using System.Windows.Controls;

namespace BK.WPF.CustomControls
{
    public partial class BindanblePasswordBox : UserControl
    {
        public static readonly DependencyProperty PasswordProperty =
            DependencyProperty.Register("Password", typeof(SecureString), typeof(BindanblePasswordBox));

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

        public BindanblePasswordBox()
        {
            InitializeComponent();
            PswdBox.PasswordChanged += PswdBox_PasswordChanged;
        }

        private void PswdBox_PasswordChanged(object sender, RoutedEventArgs e)
        {
            var secure = new SecureString();
            foreach (var c in PswdBox.Password)
            {
                secure.AppendChar(c);
            }
            Password = secure;
        }
    }
}

Usage of Version 1:

<local:BindanblePasswordBox Width="150" HorizontalAlignment="Center"
                            VerticalAlignment="Center"
                            Password="{Binding Password, Mode=OneWayToSource}"/>

BindablePasswordBox.xaml.cs (Version 2 - Has two-way binding support.)

public partial class BindablePasswordBox : UserControl
{
    public static readonly DependencyProperty PasswordProperty =
        DependencyProperty.Register("Password", typeof(SecureString), typeof(BindablePasswordBox),
        new PropertyMetadata(PasswordChanged));

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

    public BindablePasswordBox()
    {
        InitializeComponent();
        PswdBox.PasswordChanged += PswdBox_PasswordChanged;
    }

    private void PswdBox_PasswordChanged(object sender, RoutedEventArgs e)
    {
        var secure = new SecureString();
        foreach (var c in PswdBox.Password)
        {
            secure.AppendChar(c);
        }
        if (Password != secure)
        {
            Password = secure;
        }
    }

    private static void PasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var pswdBox = d as BindablePasswordBox;
        if (pswdBox != null && e.NewValue != e.OldValue)
        {
            var newValue = e.NewValue as SecureString;
            if (newValue == null)
            {
                return;
            }

            var unmanagedString = IntPtr.Zero;
            string newString;
            try
            {
                unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(newValue);
                newString = Marshal.PtrToStringUni(unmanagedString);
            }
            finally
            {
                Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
            }

            var currentValue = pswdBox.PswdBox.Password;
            if (currentValue != newString)
            {
                pswdBox.PswdBox.Password = newString;
            }
        }
    }
}

Usage of Version 2:

<local:BindanblePasswordBox Width="150" HorizontalAlignment="Center"
                            VerticalAlignment="Center"
                            Password="{Binding Password, Mode=TwoWay}"/>

I have done like:

XAML:

<PasswordBox x:Name="NewPassword" PasswordChanged="NewPassword_PasswordChanged"/>
<!--change tablenameViewSource: yours!-->
<Grid DataContext="{StaticResource tablenameViewSource}" Visibility="Hidden">
        <TextBox x:Name="Password" Text="{Binding password, Mode=TwoWay}"/>
</Grid>

C#:

private void NewPassword_PasswordChanged(object sender, RoutedEventArgs e)
    {
        try
        {
           //change tablenameDataTable: yours! and tablenameViewSource: yours!
           tablenameDataTable.Rows[tablenameViewSource.View.CurrentPosition]["password"] = NewPassword.Password;
        }
        catch
        {
            this.Password.Text = this.NewPassword.Password;
        }
    }

It works for me!


I used this method and passed the password box, although this does violate the MVVM it was essential for me because I was using a content control with data template for my login within my shell which is a complex shell enviroment. So accessing the code behind of the shell would have been crap.

Passing the passwordbox I would think is same as accessing control from code behind as far as I know. I agree passwords, dont keep in memory etc In this implementation I don't have property for password in view model.

Button Command

Command="{Binding Path=DataContext.LoginCommand, ElementName=MyShell}" CommandParameter="{Binding ElementName=PasswordBox}"

ViewModel

private void Login(object parameter)
{
    System.Windows.Controls.PasswordBox p = (System.Windows.Controls.PasswordBox)parameter;
    MessageBox.Show(p.Password);
}

Examples related to c#

How can I convert this one line of ActionScript to C#? Microsoft Advertising SDK doesn't deliverer ads How to use a global array in C#? How to correctly write async method? C# - insert values from file into two arrays Uploading into folder in FTP? Are these methods thread safe? dotnet ef not found in .NET Core 3 HTTP Error 500.30 - ANCM In-Process Start Failure Best way to "push" into C# array

Examples related to wpf

Error: the entity type requires a primary key Reportviewer tool missing in visual studio 2017 RC Pass command parameter to method in ViewModel in WPF? Calling async method on button click Setting DataContext in XAML in WPF How to resolve this System.IO.FileNotFoundException System.Windows.Markup.XamlParseException' occurred in PresentationFramework.dll? Binding an Image in WPF MVVM How to bind DataTable to Datagrid Setting cursor at the end of any text of a textbox

Examples related to mvvm

Vue.js—Difference between v-model and v-bind Pass command parameter to method in ViewModel in WPF? [Vue warn]: Cannot find element Binding an Image in WPF MVVM Binding ComboBox SelectedItem using MVVM What is difference between MVC, MVP & MVVM design pattern in terms of coding c# How to make all controls resize accordingly proportionally when window is maximized? Add directives from directive in AngularJS Wpf DataGrid Add new row Close Window from ViewModel

Examples related to wpf-controls

How to create/make rounded corner buttons in WPF? Formatting text in a TextBlock How do I make XAML DataGridColumns fill the entire DataGrid? What is The difference between ListBox and ListView How to display the current time and date in C# Simple (I think) Horizontal Line in WPF? WPF: ItemsControl with scrollbar (ScrollViewer) Align items in a stack panel? Wpf control size to content? How to bind to a PasswordBox in MVVM

Examples related to passwords

Your password does not satisfy the current policy requirements Laravel Password & Password_Confirmation Validation Default password of mysql in ubuntu server 16.04 mcrypt is deprecated, what is the alternative? What is the default root pasword for MySQL 5.7 MySQL user DB does not have password columns - Installing MySQL on OSX Changing an AIX password via script? Hide password with "•••••••" in a textField How to create a laravel hashed password Enter export password to generate a P12 certificate