我遇到了绑定到密码盒的问题。这似乎是一个安全风险,但我正在使用MVVM模式,所以我希望绕过这个。我在这里发现了一些有趣的代码(有人使用过这个或类似的代码吗?)

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

从技术上讲,它看起来很棒,但我不确定如何检索密码。

我基本上有属性在我的LoginViewModel用户名和密码。用户名是好的,正在工作,因为它是一个文本框。

我使用上面的代码,并输入这个

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

当我有PasswordBox作为一个文本框和绑定路径=密码,然后在我的LoginViewModel属性更新。

我的代码非常简单,基本上我有一个命令为我的按钮。当我按下它CanLogin被调用,如果它返回真,它调用Login。 你可以看到,我检查了我的用户名属性,这很好。

在登录我发送到我的服务的用户名和密码,用户名包含数据从我的视图,但密码是空|空

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

这就是我正在做的

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

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

我有我的文本框,这是没有问题的,但在我的ViewModel密码是空的。

是我做错了什么还是漏了一步?

我放了一个断点,果然代码进入静态助手类,但它从不更新我的ViewModel中的密码。


当前回答

你可以用附加属性来做,看到了吗。PasswordBox with MVVM

其他回答

对于任何意识到这种实现带来的风险的人来说,要让密码同步到您的ViewModel,只需添加Mode=OneWayToSource。

XAML

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

一个不违反MVVM模式的简单解决方案是在ViewModel中引入一个获取密码的事件(或委托)。

在ViewModel中:

public event eventandler <HarvestPasswordEventArgs> HarvestPassword;

使用这些EventArgs:

class HarvestPasswordEventArgs : EventArgs
{
    public string Password;
}

在View中,订阅创建ViewModel时的事件,并填写密码值。

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

在ViewModel中,当你需要密码时,你可以触发事件并从那里获取密码:

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

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

LoginHelpers.Login(Username, pwargs.Password);

您可以在WPF应用程序框架(WAF)项目的ViewModel样例应用程序中找到PasswordBox的解决方案。

然而,犹斯丁是对的。不要在View和ViewModel之间以纯文本的形式传递密码。请使用SecureString代替(参见MSDN PasswordBox)。

你可以使用这个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>

该命令的执行方法:

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

这需要将System.Windows.Interactivity程序集添加到项目中,并通过xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"引用它。

我使用的是简洁的mvvm友好的解决方案,还没有提到。首先,我在XAML中命名PasswordBox:

<PasswordBox x:Name="Password" />

然后我在视图构造函数中添加了一个方法调用:

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

就是这样。当视图模型通过DataContext附加到视图时,它将收到通知,当它被分离时,它将收到另一个通知。此通知的内容可以通过lambdas进行配置,但通常它只是视图模型上的setter或方法调用,将有问题的控件作为参数传递。

通过使用视图公开接口而不是子控件,可以很容易地使它对mvvm友好。

上面的代码依赖于我博客上发布的helper类。