我遇到了绑定到密码盒的问题。这似乎是一个安全风险,但我正在使用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中的密码。
一个不违反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);
虽然我同意避免将密码存储在任何地方很重要,但我仍然需要能够在没有视图的情况下实例化视图模型,并针对它执行测试。
对我来说,有效的解决方案是注册PasswordBox。Password函数,并让视图模型在执行登录代码时调用它。
这意味着视图隐藏代码中的一行代码。
在我的Login中。xaml我有
<PasswordBox x:Name="PasswordBox"/>
在Login.xaml.cs中
LoginViewModel.PasswordHandler = () => PasswordBox.Password;
然后在LoginViewModel.cs我有PasswordHandler定义
public Func<string> PasswordHandler { get; set; }
当需要登录时,代码调用处理程序从视图中获取密码…
bool loginResult = Login(Username, PasswordHandler());
这样,当我想要测试视图模型时,我可以简单地将PasswordHandler设置为一个匿名方法,让我在测试中交付我想要使用的任何密码。
好吧,我的答案更简单,只是在MVVM模式
在类视图模型中
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;
}
win提供的PasswordBox或XCeedtoolkit提供的WatermarkPasswordBox的password属性生成一个RoutedEventArgs,以便您可以绑定它。
现在在xmal视图中
<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>