我的 WPF PasswordBox 有什么问题?
What is wrong with my WPF PasswordBox?
我有一个登录视图,其中 PasswordBox
标记如下:
<PasswordBox x:Name="PasswordText" Width="Auto" Margin="5" PasswordChanged="PasswordTextOnPasswordChanged" />
它的问题是插入符仍然在文本框的最左边;它不会在您键入时向前移动,因此您键入的最后一个字符将成为文本框中的第一个字符。例如。当我输入密码“123”时,PasswordBox
的内容转换为普通字符串后是“321”。它不是转换代码,因为如果我用密码预先填充控件,即不涉及输入,它的内容将转换为正确的纯字符串。
这是怎么回事?对我来说插入符号不跟随输入似乎有问题。
幕后(即代码隐藏)我有:
private void PasswordTextOnPasswordChanged(object sender, RoutedEventArgs e)
{
if (!_suppressPasswordChanged)
{
((LoginFormViewModel)DataContext).Password = PasswordText.SecurePassword;
}
}
_suppressPasswordChanged
只是为了避免在我明确设置密码时触发 PasswordTextOnPasswordChanged
处理程序。
public void SetPassword(string password)
{
try
{
_suppressPasswordChanged = true;
PasswordText.Password = password;
}
finally
{
_suppressPasswordChanged = false;
}
}
A PasswordBox
没有数据绑定,因此需要视图中的代码在用户在该框中键入内容时更新视图模型。我最初有这个事件处理程序:
private void PasswordTextOnPasswordChanged(object sender, RoutedEventArgs e)
{
((LoginFormViewModel)DataContext).Password = PasswordText.SecurePassword;
}
然后我希望能够在视图模型中设置Password
属性,并且不得不添加这个视图方法:
public void SetPassword(string password)
{
PasswordText.Password = password;
}
从 setter 调用:
set
{
if (value == _password) return;
_password = value;
((LoginFormPopup)View).SetPassword(_password.ToClearString());
OnPropertyChanged();
}
这以 SetPassword
触发 PasswordTextOnPasswordChanged
结束,它再次调用 setter,正常情况下应该如此,但在代码递归触发时不会。我为防止这些方法相互调用而进行的第一次令人尴尬的尝试是:
private bool suppressPasswordChanged;
private void PasswordTextOnPasswordChanged(object sender, RoutedEventArgs e)
{
if (!suppressPasswordChanged)
{
((LoginFormViewModel)DataContext).Password = PasswordText.SecurePassword;
}
}
public void SetPassword(string password)
{
try
{
suppressPasswordChanged = true;
PasswordText.Password = password;
}
finally
{
suppressPasswordChanged = false;
}
}
但是因为 SetPassword
总是在其 finally
中重置 suppressPasswordChanged
,它仍然总是会从 PasswordTextOnPasswordChanged
.
调用
我目前有效但可能有点臭的解决方案是将设置 'do-not-call' 标志的责任移交给事件处理程序:
private bool _textChangedEventBusy;
private void PasswordTextOnPasswordChanged(object sender, RoutedEventArgs e)
{
try
{
_textChangedEventBusy = true;
((LoginFormViewModel)DataContext).Password = PasswordText.SecurePassword;
}
finally
{
_textChangedEventBusy = false;
}
}
public void SetPassword(string password)
{
if (!_textChangedEventBusy)
{
PasswordText.Password = password;
}
}
现在,SetPassword
只会从视图模型中的 setter 调用,然后将插入符号设置到文本的开头是理想的。
我有一个登录视图,其中 PasswordBox
标记如下:
<PasswordBox x:Name="PasswordText" Width="Auto" Margin="5" PasswordChanged="PasswordTextOnPasswordChanged" />
它的问题是插入符仍然在文本框的最左边;它不会在您键入时向前移动,因此您键入的最后一个字符将成为文本框中的第一个字符。例如。当我输入密码“123”时,PasswordBox
的内容转换为普通字符串后是“321”。它不是转换代码,因为如果我用密码预先填充控件,即不涉及输入,它的内容将转换为正确的纯字符串。
这是怎么回事?对我来说插入符号不跟随输入似乎有问题。
幕后(即代码隐藏)我有:
private void PasswordTextOnPasswordChanged(object sender, RoutedEventArgs e)
{
if (!_suppressPasswordChanged)
{
((LoginFormViewModel)DataContext).Password = PasswordText.SecurePassword;
}
}
_suppressPasswordChanged
只是为了避免在我明确设置密码时触发 PasswordTextOnPasswordChanged
处理程序。
public void SetPassword(string password)
{
try
{
_suppressPasswordChanged = true;
PasswordText.Password = password;
}
finally
{
_suppressPasswordChanged = false;
}
}
A PasswordBox
没有数据绑定,因此需要视图中的代码在用户在该框中键入内容时更新视图模型。我最初有这个事件处理程序:
private void PasswordTextOnPasswordChanged(object sender, RoutedEventArgs e)
{
((LoginFormViewModel)DataContext).Password = PasswordText.SecurePassword;
}
然后我希望能够在视图模型中设置Password
属性,并且不得不添加这个视图方法:
public void SetPassword(string password)
{
PasswordText.Password = password;
}
从 setter 调用:
set
{
if (value == _password) return;
_password = value;
((LoginFormPopup)View).SetPassword(_password.ToClearString());
OnPropertyChanged();
}
这以 SetPassword
触发 PasswordTextOnPasswordChanged
结束,它再次调用 setter,正常情况下应该如此,但在代码递归触发时不会。我为防止这些方法相互调用而进行的第一次令人尴尬的尝试是:
private bool suppressPasswordChanged;
private void PasswordTextOnPasswordChanged(object sender, RoutedEventArgs e)
{
if (!suppressPasswordChanged)
{
((LoginFormViewModel)DataContext).Password = PasswordText.SecurePassword;
}
}
public void SetPassword(string password)
{
try
{
suppressPasswordChanged = true;
PasswordText.Password = password;
}
finally
{
suppressPasswordChanged = false;
}
}
但是因为 SetPassword
总是在其 finally
中重置 suppressPasswordChanged
,它仍然总是会从 PasswordTextOnPasswordChanged
.
我目前有效但可能有点臭的解决方案是将设置 'do-not-call' 标志的责任移交给事件处理程序:
private bool _textChangedEventBusy;
private void PasswordTextOnPasswordChanged(object sender, RoutedEventArgs e)
{
try
{
_textChangedEventBusy = true;
((LoginFormViewModel)DataContext).Password = PasswordText.SecurePassword;
}
finally
{
_textChangedEventBusy = false;
}
}
public void SetPassword(string password)
{
if (!_textChangedEventBusy)
{
PasswordText.Password = password;
}
}
现在,SetPassword
只会从视图模型中的 setter 调用,然后将插入符号设置到文本的开头是理想的。