Question

Salut les gens Stackoverflow. Je travaille avec MVVM, j'ai ViewModel appeler UserViewModel avec un mot de passe de la propriété. Dans le Afficher un PasswordBox de contrôle.

<PasswordBox x:Name="txtPassword" Password="{Binding Password}" />

Mais cette XAML ne fonctionne pas. Comment faites-vous la liaison ?? Aidez-moi, s'il vous plaît!!

Était-ce utile?

La solution

Pour des raisons de sécurité la propriété de mot de passe est une propriété de dépendance et donc vous ne pouvez pas lier à elle. Malheureusement, vous devrez effectuer la liaison dans le code derrière l'ancienne (registre pour l'événement OnPropertyChanged et mettre à jour la valeur par le code ...)


Je recherche rapide me amène à ce blog qui montre comment écrire une propriété attachée à contourner la question. Que ce soit en vaut la peine ou non mais dépend vraiment de votre aversion pour le code-behind.

Autres conseils

Vous pouvez toujours écrire un contrôle qui enveloppe le mot de passe et ajoute une propriété de dépendance de la propriété de mot de passe.

Je voudrais simplement utiliser le code derrière, mais si vous devez vous pouvez faire quelque chose comme:

public class BindablePasswordBox : Decorator
{
    public static readonly DependencyProperty PasswordProperty =
        DependencyProperty.Register("Password", typeof(string), typeof(BindablePasswordBox));

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

    public BindablePasswordBox()
    {
        Child = new PasswordBox();
        ((PasswordBox)Child).PasswordChanged += BindablePasswordBox_PasswordChanged;
    }

    void BindablePasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
    {
        Password = ((PasswordBox)Child).Password;
    }

}

Il y a un problème avec le BindablePasswordBox. Il ne fonctionne que dans un sens, PasswordBox à PasswordProperty. Ci-dessous est une version modifiée de celui-ci qui fonctionne dans les deux sens. Il enregistre un PropertyChangedCallback et met à jour le mot de passe PasswordBox lorsqu'elle est appelée. J'espère que quelqu'un trouve cela utile.

public class BindablePasswordBox : Decorator
{
    public static readonly DependencyProperty PasswordProperty = DependencyProperty.Register("Password", typeof(string), typeof(BindablePasswordBox), new PropertyMetadata(string.Empty, OnDependencyPropertyChanged));
    public string Password
    {
        get { return (string)GetValue(PasswordProperty); }
        set { SetValue(PasswordProperty, value); }
    }

    private static void OnDependencyPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
    {
        BindablePasswordBox p = source as BindablePasswordBox;
        if (p != null)
        {
            if (e.Property == PasswordProperty)
            {
                var pb = p.Child as PasswordBox;
                if (pb != null)
                {
                    if (pb.Password != p.Password)
                        pb.Password = p.Password;
                }
            }
        }
    }

    public BindablePasswordBox()
    {
        Child = new PasswordBox();
        ((PasswordBox)Child).PasswordChanged += BindablePasswordBox_PasswordChanged;
    }

    void BindablePasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
    {
        Password = ((PasswordBox)Child).Password;
    }
}

Pour éviter d'avoir le mot de passe disponible dans la mémoire sous forme de texte à tout moment, je donne la valeur en tant que paramètre à ma commande.

<Label>User Name</Label>
<TextBox Text="{Binding UserName}" />
<Label>Password</Label>
<PasswordBox Name="PasswordBox" />
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0 16 0 0">
    <Button Margin="0 0 8 0" MinWidth="65" 
            Command="{Binding LoginAccept}" 
            CommandParameter="{Binding ElementName=PasswordBox}">
        Login
    </Button>
    <Button MinWidth="65" Command="{Binding LoginCancel}">Cancel</Button>
</StackPanel>

Ensuite, dans mon modèle de vue.

public DelegateCommand<object> LoginAccept { get; private set; }
public DelegateCommand<object> LoginCancel { get; private set; }

public LoginViewModel {
    LoginAccept = new DelegateCommand<object>(o => OnLogin(o), (o) => IsLoginVisible);
    LoginCancel = new DelegateCommand<object>(o => OnLoginCancel(), (o) => IsLoginVisible);
}

private void OnLogin(object o)
{
    var passwordBox = (o as System.Windows.Controls.PasswordBox);
    var password = passwordBox.SecurePassword.Copy();
    passwordBox.Clear();
    ShowLogin = false;
    var credential = new System.Net.NetworkCredential(UserName, password);
}

private void OnLoginCancel()
{
    ShowLogin = false;
}

Alors qu'il serait judicieux de fournir le SecurePassword directement à partir de la liaison, il semble toujours de fournir une valeur vide. Donc, cela ne fonctionne pas:

    <Button Margin="0 0 8 0" MinWidth="65" 
            Command="{Binding LoginAccept}" 
            CommandParameter="{Binding ElementName=PasswordBox, Path=SecurePassword}">

Vérifiez un autre thread sur la boîte de mot de passe. Il est préférable de ne pas garder le mot de passe sur un DP ou d'un bien public.

Autre fil sur PasswordBox

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top