嗨人stackoverflow。我正在使用MVVM,我有 ViewModel 使用属性密码调用UserViewModel。在视图中有一个控件PasswordBox。
<PasswordBox x:Name="txtPassword" Password="{Binding Password}" />
但是这个xaml不起作用。你怎么做绑定?请帮忙!!
答案 0 :(得分:13)
出于安全原因,Password属性不是依赖项属性,因此您无法绑定它。不幸的是,你需要在老式方式背后的代码中执行绑定(注册OnPropertyChanged事件并通过代码更新值...)
我快速搜索将我带到this blog post,其中显示了如何编写附加属性来回避问题。这是否值得做,但实际上取决于你对代码隐藏的厌恶。
答案 1 :(得分:5)
您始终可以编写一个包装密码的控件,并为Password属性添加依赖项属性。
我只会使用代码,但如果你必须,你可以做类似的事情:
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;
}
}
答案 2 :(得分:4)
BindablePasswordBox存在问题。它只能在一个方向上工作,PasswordBox到PasswordProperty。以下是它的两个方向的修改版本。它注册一个PropertyChangedCallback并在调用时更新PasswordBox的密码。 我希望有人觉得这很有用。
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;
}
}
答案 3 :(得分:2)
为避免在内存中将密码作为纯文本提供,我将该值作为参数提供给我的命令。
<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>
然后在我的视图模型中。
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;
}
虽然直接从绑定提供SecurePassword是有意义的,但它似乎总是提供一个空值。所以这不起作用:
<Button Margin="0 0 8 0" MinWidth="65"
Command="{Binding LoginAccept}"
CommandParameter="{Binding ElementName=PasswordBox, Path=SecurePassword}">
答案 4 :(得分:0)
检查密码框中的另一个帖子。 最好不要将密码保存在任何DP或公共财产上。