最新信息/问题:下面发布的所有内容都有效(绑定PasswordBox字符串的数据),除了我的PasswordBox看起来是空的,即使它的内容是正确的。
详细信息:我有一个带有PasswordBox和DependencyProperty的UserControl。该DP可用于通过数据绑定从该PWBox设置/检索SecureString。
public partial class PasswordUserControl : UserControl
{
public SecureString Password
{
get { return (SecureString)GetValue(PasswordProperty); }
set { SetValue(PasswordProperty, value); }
}
// https://msdn.microsoft.com/en-us/library/ms750428(v=vs.110).aspx
public static readonly DependencyProperty PasswordProperty =
DependencyProperty.Register("Password", typeof(SecureString), typeof(PasswordUserControl),
new PropertyMetadata(default(SecureString)));
public PasswordUserControl()
{
InitializeComponent();
PasswordEntryBox.PasswordChanged += (sender, args) => {
Password = ((PasswordBox)sender).SecurePassword; };
}
}
简单XAML:
<UserControl x:Class="WpfClient.PasswordUserControl"
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:local="clr-namespace:WpfClient"
mc:Ignorable="d"
d:SizeToContent="true">
<StackPanel>
<DockPanel>
<Label Content="Password" Margin="0,0,5,0" DockPanel.Dock="Left"/>
<PasswordBox Name="PasswordEntryBox" Width="200" DockPanel.Dock="Right" />
</DockPanel>
</StackPanel>
在另一个位置简单使用该控件:
<local:PasswordUserControl Password="{Binding Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
"绑定密码"感觉进入SecureString:
public SecureString Password
{
get { return m_Password; }
set
{
m_Password = value;
RaisePropertyChanged("Password");
}
}
问题:数据绑定似乎是双向的;我得到了正确的用户输入(触发登录有效)。PropertyChanged也起作用:对于添加的每个字符,我都会得到一个属性更新。
不起作用的是:实际的PasswordBox看起来是空的。如果我先在代码中设置Password并查看控件,它不会为已经输入的数据绑定文本显示一堆匿名圆圈字符(但字符串本身是正确的——调试器会这么说,实际登录有效!)。如果我手动在框中输入密码文本,我确实会得到匿名字符作为输入,但我的输入不会添加到所谓的数据绑定的现有字符串中。它似乎擦除了数据绑定字符串,并从头开始创建一个新字符串。
我做错了什么?
要想查看PasswordBox
中的任何密码字符,需要将其Password
属性设置为string
。这意味着您需要从SecureString
对象中提取纯密码字符串。
只要Password
依赖项属性设置为新的SecureString
值,就应该执行此操作。
您可以将PropertyChangedCallback
添加到依赖属性中,并按如下方式实现UserControl
:
public partial class PasswordUserControl : UserControl
{
public SecureString Password
{
get { return (SecureString)GetValue(PasswordProperty); }
set { SetValue(PasswordProperty, value); }
}
public static readonly DependencyProperty PasswordProperty =
DependencyProperty.Register("Password", typeof(SecureString), typeof(PasswordUserControl),
new PropertyMetadata(default(SecureString), new PropertyChangedCallback(OnPasswordChanged)));
public PasswordUserControl()
{
InitializeComponent();
PasswordEntryBox.PasswordChanged += PasswordEntryBox_PasswordChanged;
}
private bool _handleEvent = true;
private void PasswordEntryBox_PasswordChanged(object sender, RoutedEventArgs e)
{
if(_handleEvent)
Password = ((PasswordBox)sender).SecurePassword;
}
private static void OnPasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
SecureString ss = e.NewValue as SecureString;
if(ss != null)
{
PasswordUserControl control = d as PasswordUserControl;
if(control != null)
{
control._handleEvent = false;
control.PasswordEntryBox.Password = ConvertToUnsecureString(ss);
control._handleEvent = true;
}
}
}
public static string ConvertToUnsecureString(SecureString securePassword)
{
if (securePassword == null)
throw new ArgumentNullException("securePassword");
IntPtr unmanagedString = IntPtr.Zero;
try
{
unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(securePassword);
return Marshal.PtrToStringUni(unmanagedString);
}
finally
{
Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
}
}
}
LoginPassword.Password = Globals.credentials == null ? "": new NetworkCredential("", Globals.credentials.SecurePassword).Password;
只需在xaml.cs文件中放一行即可。将密码框命名为"登录密码"。