Search code examples
wpfmvvmdatatemplatepasswordbox

MVVM Passwordbox with data template


How can I get password from passwordbox?
1. I dont want to violate MVVM pattern (at least not to much)
2. I cant use code-behind because I use data templates to create my views. I have to use them because I am making window that contains pages. So I store page viewmodels in my window viewmodel and attach them to ContentControl when I need to navigate to any of them. I have to do this as I share my model between them.
3. I want some level of security as well, so I dont want to "hack" password box in order to bind password property.
Is this impossible?

I dont use any MVVM-frameworks. And I know there are lots of questions about passwordbox and MVVM but none of them deal with data templates. Even more, I have 2 passwordboxes in my view (second for "confirm password") and I cant just pass PasswordBox as CommandParameter (because I have 2 of them and passing element containing them is absolutely barbaric)


Solution

  • Serious, there is no real mvvm solution for the passwordbox, which maintains the security like without mvvm.

    In my opinion the best / least bad way of working with the password box in an mvvm-built application is to give the whole passwordbox control to your viewmodel via a commandparameter (like in a login/register button) and hand it over to your internal classes/services until you really need to get the password out for a webservice or something like that.

    It definitely breaks the mvvm-pattern because your viewmodel knowns about a control, but it's the most secure solution, which can be easily implement in most mvvm-built applications.

    EDIT: You can easily pass two or more passwordboxes via the command parameter if you need them. (Like for a register dialog, where users have to type their password two times and they have to match.) This can be done via MultiBinding of the Commandparameter:

    <Button.CommandParameter>
        <MultiBinding Converter="{local:ItemsToListConverter}">
            <Binding ElementName="nameOfPasswordBox1" />
            <Binding ElementName="nameOfPasswordBox2" />
        </MultiBinding>
    </Button.CommandParameter>
    

    The Converter just returns all values as a new List:

    [MarkupExtensionReturnType(typeof(ItemsToListConverter))]
    public class ItemsToListConverter : MarkupExtension, IMultiValueConverter
    {
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return this;
        }
    
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (values == null) return values;
            return values.ToList();
        }
    
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    

    And in your ViewModel you have your normal ICommand which takes an object as parameter. You can there cast that object to a list of PasswordBoxes. (In my example it's a RegisterCommand with a Method 'Register'):

    private void Register(object obj)
    {
        IEnumerable<PasswordBox> passwordBoxes = (obj as IList).Cast<PasswordBox>();
        //Do whatever with your PasswordBoxes =)
    }