c# - wpf passwordbox text




Comment lier à un PasswordBox dans MVVM (19)

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}"/>

J'ai rencontré un problème avec la liaison à un PasswordBox. Il semble que ce soit un risque de sécurité mais j'utilise le pattern MVVM donc je souhaite contourner cela. J'ai trouvé un code intéressant ici (quelqu'un a-t-il utilisé ceci ou quelque chose de similaire?)

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

Techniquement, ça a l'air génial, mais je ne sais pas trop comment récupérer le mot de passe.

J'ai fondamentalement des propriétés dans mon LoginViewModel pour le LoginViewModel d' Username et le Password . Username est correct et fonctionne comme s'il s'agissait d'un TextBox .

J'ai utilisé le code ci-dessus comme indiqué et entré cette

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

Quand j'ai eu le PasswordBox comme TextBox et Binding Path=Password alors la propriété dans mon LoginViewModel été mise à jour.

Mon code est très simple, fondamentalement j'ai une Command pour mon Button . Quand j'appuie sur CanLogin il est appelé et s'il renvoie vrai, il appelle Login .
Vous pouvez voir que je vérifie ma propriété pour le nom d' Username ici qui fonctionne très bien.

Dans Login j'envoie à mon service un nom d' Username et un Password , le nom d' Username contient des données de ma View mais le Password est 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 { }
    }

C'est ce que je fais

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

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

J'ai mon TextBox , ce n'est pas un problème, mais dans mon ViewModel le Password est vide.

Est-ce que je fais quelque chose de mal ou si je manque une étape?

Je mets un point d'arrêt et bien sûr le code entre dans la classe d'aide statique, mais il ne met jamais à jour mon Password de Password dans mon ViewModel .


Bien que je sois d'accord qu'il est important d'éviter de stocker le mot de passe n'importe où, j'ai toujours besoin de la possibilité d'instancier le modèle de vue sans vue et d'exécuter mes tests par rapport à celui-ci.

La solution qui a fonctionné pour moi était d'enregistrer la fonction PasswordBox.Password avec le modèle de vue, et le modèle de vue l'invoquer lors de l'exécution du code de connexion.

Cela signifie une ligne de code dans le codebehind de la vue.

Donc, dans mon Login.xaml j'ai

<PasswordBox x:Name="PasswordBox"/>

et dans Login.xaml.cs j'ai

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

puis dans LoginViewModel.cs j'ai le PasswordHandler défini

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

et quand la connexion doit se produire, le code invoque le gestionnaire pour obtenir le mot de passe de la vue ...

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

De cette façon, quand je veux tester le viewmodel, je peux simplement définir PasswordHandler à une méthode anonyme qui me permet de fournir le mot de passe que je veux utiliser dans le test.


Cette implémentation est légèrement différente. Vous passez une boîte de mot de passe à la liaison View thru d'une propriété dans ViewModel, elle n'utilise aucun paramètre de commande. Le ViewModel reste ignorant de la vue. J'ai un projet VB vs 2010 qui peut être téléchargé à partir de SkyDrive. Wpf MvvM PassWordBox Exemple.zip https://skydrive.live.com/redir.aspx?cid=e95997d33a9f8d73&resid=E95997D33A9F8D73!511

La façon dont j'utilise PasswordBox dans une application Wvf MvvM est assez simpliste et fonctionne bien pour moi. Cela ne veut pas dire que je pense que c'est la bonne façon ou la meilleure. C'est juste une implémentation de l'utilisation de PasswordBox et du pattern MvvM.

Basicly Vous créez une propriété publique readonly à laquelle View peut se lier en tant que PasswordBox (Le contrôle réel) Exemple:

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

J'utilise un backing field juste pour faire l'auto initialisation de la propriété.

Ensuite, à partir de Xaml, vous liez le contenu d'un ContentControl ou d'un conteneur de contrôle. Exemple:

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

De là, vous avez le contrôle total de la boîte de mot de passe J'utilise aussi un PasswordAccessor (juste une fonction de chaîne) pour retourner la valeur du mot de passe lors de la connexion ou tout ce que vous voulez pour le mot de passe. Dans l'exemple, j'ai une propriété publique dans un modèle d'objet utilisateur générique. Exemple:

Public Property PasswordAccessor() As Func(Of String)

Dans l'objet utilisateur, la propriété de chaîne de mot de passe est en lecture seule sans magasin de sauvegarde, elle renvoie simplement le mot de passe du PasswordBox. Exemple:

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

Ensuite, dans le ViewModel, je m'assure que l'Accessor est créé et défini sur la propriété PasswordBox.Password 'Exemple:

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

Quand j'ai besoin de la chaîne de mot de passe pour la connexion, je reçois la propriété User Objects Password qui invoque vraiment la fonction pour saisir le mot de passe et le retourner, alors le mot de passe n'est pas stocké par l'objet User. Exemple: serait dans le 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

Ça devrait le faire. Le ViewModel n'a besoin d'aucune connaissance des contrôles de View. La vue se lie juste à la propriété dans le ViewModel, pas différente de la liaison de vue à une image ou une autre ressource. Dans ce cas, cette ressource (propriété) est juste un usercontrol. Il permet de tester lorsque ViewModel crée et possède la propriété et que la propriété est indépendante de la vue. En ce qui concerne la sécurité, je ne sais pas si cette implémentation est bonne. Mais en utilisant une fonction, la valeur n'est pas stockée dans la propriété elle-même juste accessible par la propriété.


Désolé, mais vous le faites mal.

Les gens devraient avoir la ligne de sécurité suivante tatouée à l'intérieur de leurs paupières:
Ne gardez jamais les mots de passe en texte clair en mémoire.

La raison pour laquelle WPF / Silverlight PasswordBox n'expose pas un DP pour la propriété Password est liée à la sécurité.
Si WPF / Silverlight devait conserver un DP pour le mot de passe, il faudrait que l'infrastructure conserve le mot de passe lui-même non crypté en mémoire. Ce qui est considéré comme un vecteur d'attaque de sécurité assez gênant. PasswordBox utilise une sorte de mémoire cryptée et la seule façon d'accéder au mot de passe est la propriété CLR.

Je suggère que lors de l'accès à la propriété CLR PasswordBox.Password, vous évitez de le placer dans n'importe quelle variable ou comme valeur pour n'importe quelle propriété.
Garder votre mot de passe en texte brut sur la RAM de la machine cliente est un non-non.
Alors débarrassez-vous de cette "chaîne publique Password {get; set;}" que vous avez là-haut.

Lorsque vous accédez à PasswordBox.Password, sortez-le et envoyez-le au serveur dès que possible. Ne gardez pas la valeur du mot de passe et ne le traitez pas comme vous le feriez avec n'importe quel autre texte de machine client. Ne gardez pas les mots de passe en clair.

Je sais que cela casse le modèle MVVM, mais vous ne devriez jamais vous lier à PasswordBox.Password Attaché DP, stocker votre mot de passe dans le ViewModel ou d'autres manigances similaires.

Si vous cherchez une solution sur-architecturée, en voici une:
1. Créez l'interface IHavePassword avec une méthode qui renvoie le texte en clair du mot de passe.
2. Demandez à UserControl d'implémenter une interface IHavePassword.
3. Enregistrez l'instance UserControl avec votre IoC en implémentant l'interface IHavePassword.
4. Quand une demande de serveur nécessitant votre mot de passe est en cours, appelez votre IoC pour l'implémentation de IHavePassword et seulement pour obtenir le mot de passe tant convoité.

Juste mon point de vue.

-- Justin


J'ai pensé que je mettrais ma solution dans le mix, puisque c'est un problème si commun ... et avoir beaucoup d'options est toujours une bonne chose.

J'ai simplement enveloppé un PasswordBox dans un UserControl et implémenté un DependencyProperty pour pouvoir lier. Je fais tout ce que je peux pour éviter de stocker du texte en clair dans la mémoire, donc tout est fait via une SecureString et la propriété PasswordBox.Password . Pendant la boucle foreach , chaque personnage est exposé, mais il est très bref. Honnêtement, si vous craignez que votre application WPF soit compromise par cette brève exposition, vous avez des problèmes de sécurité plus importants qui devraient être traités.

La beauté de ceci est que vous ne cassez aucune règle MVVM, même les règles "puristes", puisqu'il s'agit d'un UserControl , donc il est autorisé à avoir du code-behind. Lorsque vous l'utilisez, vous pouvez avoir une communication pure entre View et ViewModel sans que VideModel soit au courant d'une partie de View ou de la source du mot de passe. Assurez-vous simplement que vous êtes lié à SecureString dans votre 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 - Aucun support de liaison bidirectionnelle.)

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}"/>

J'ai posté un GIST here qui est une boîte de mot de passe bindable.

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;
        }
    }
}

Mes 2 cents:

J'ai développé une fois une boîte de dialogue de connexion typique (boîtes d'utilisateur et mot de passe, plus le bouton "Ok") en utilisant WPF et MVVM. J'ai résolu le problème de liaison de mot de passe en passant simplement le contrôle PasswordBox lui-même en tant que paramètre à la commande attachée au bouton "Ok". Donc, dans la vue que j'avais:

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

Et dans le ViewModel, la méthode Execute de la commande attachée était la suivante:

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

Cela viole légèrement le modèle MVVM puisque maintenant le ViewModel sait quelque chose sur la façon dont la vue est implémentée, mais dans ce projet particulier je pouvais me le permettre. J'espère que c'est utile pour quelqu'un aussi.


Peut-être qu'il me manque quelque chose, mais il semble que la plupart de ces solutions compliquent trop les choses et éliminent les pratiques sécurisées.

Cette méthode ne viole pas le modèle MVVM et maintient une sécurité complète. Oui, techniquement c'est du code derrière, mais ce n'est rien de plus qu'une liaison "cas particulier". Le ViewModel n'a toujours pas connaissance de l'implémentation de View, ce qui est dans mon esprit si vous essayez de passer le PasswordBox dans le ViewModel.

Code Behind! = Violation automatique MVVM. Tout dépend de ce que vous en faites. Dans ce cas, nous sommes en train de coder manuellement une liaison, donc tout est considéré comme faisant partie de l'implémentation de l'interface utilisateur et est donc correct.

Dans le ViewModel, juste une simple propriété. Je l'ai fait "écrire seulement" car il ne devrait pas être nécessaire de le récupérer de l'extérieur du ViewModel pour une raison quelconque, mais ce n'est pas obligatoire. Notez que c'est une SecureString, pas seulement une chaîne.

public SecureString SecurePassword { private get; set; }

Dans le xaml, vous configurez un gestionnaire d'événements PasswordChanged.

<PasswordBox PasswordChanged="PasswordBox_PasswordChanged"/>

Dans le code derrière:

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

Avec cette méthode, votre mot de passe reste dans SecureString à tout moment et offre donc une sécurité maximale. Si vous ne vous souciez vraiment pas de la sécurité ou si vous avez besoin du mot de passe en clair pour une méthode en aval qui l'exige (remarque: la plupart des méthodes .NET nécessitant un mot de passe supportent également une option SecureString). même si vous le pensez), vous pouvez simplement utiliser la propriété Password à la place. Comme ça:

(Propriété ViewModel)

public string Password { private get; set; }

(Code derrière)

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

Si vous voulez garder les choses fortement typées, vous pouvez remplacer la distribution (dynamique) par l'interface de votre ViewModel. Mais en réalité, les liaisons de données "normales" ne sont pas fortement typées non plus, ce n'est donc pas un gros problème.

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

Donc, le meilleur de tous les mondes - votre mot de passe est sécurisé, votre ViewModel a juste une propriété comme toute autre propriété, et votre View est autonome sans références externes requises.


Une solution simple sans violer le modèle MVVM est d'introduire un événement (ou un délégué) dans le ViewModel qui récupère le mot de passe.

Dans le ViewModel :

public event EventHandler<HarvestPasswordEventArgs> HarvestPassword;

avec ces EventArgs:

class HarvestPasswordEventArgs : EventArgs
{
    public string Password;
}

dans la vue , abonnez-vous à l'événement lors de la création de ViewModel et indiquez la valeur du mot de passe.

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

Dans ViewModel , lorsque vous avez besoin du mot de passe, vous pouvez déclencher l'événement et récupérer le mot de passe à partir de là:

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

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

LoginHelpers.Login(Username, pwargs.Password);

Vous pouvez utiliser ce code XAML:

<PasswordBox Name="PasswordBox">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="PasswordChanged">
            <i:InvokeCommandAction Command="{Binding PasswordChangedCommand}" CommandParameter="{Binding ElementName=PasswordBox}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</PasswordBox>

Et cette commande exécute la méthode:

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

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"
    };

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 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.


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.


In windows universal app

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

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


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;
        }
    }


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>

ou

<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>

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

        </Grid>
    </ContentControl>
</UserControl>

using System;
using System.Windows;
using System.Windows.Controls;
using Caliburn.Micro;

namespace Elections.Server.Handler.ViewModels
{
    public class LoginViewModel : PropertyChangedBase
    {
        MainViewModel _mainViewModel;
        public void SetMain(MainViewModel mainViewModel)
        {
            _mainViewModel = mainViewModel;
        }

        public void Login(Object password)
        {
            var pass = (PasswordBox) password;
            MessageBox.Show(pass.Password);

            //_mainViewModel.ScreenView = _mainViewModel.ControlPanelView;
            //_mainViewModel.TitleWindow = "Panel de Control";
            //HandlerBootstrapper.Title(_mainViewModel.TitleWindow);
        }
    }
}

;) easy!







passwords