前期信息/问题: 下面发布的所有内容都可以工作(数据绑定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}" />
&#34;绑定密码&#34;感觉到SecureString:
public SecureString Password
{
get { return m_Password; }
set
{
m_Password = value;
RaisePropertyChanged("Password");
}
}
问题: 数据绑定似乎在两个方面都有效;我得到了正确的用户输入(触发登录工作)。 PropertyChanged也有效:对于添加的每个字符,我都会获得属性更新。
什么行不通:实际的PasswordBox看起来是空的。如果我先在代码中设置密码并查看控件,它就不会显示已经输入的数据绑定文本的一堆匿名圆圈字符(但字符串本身是正确的 - 调试器说的是这样且实际的登录工作!)。如果我手动在框中输入密码文本,我会为我的条目获取匿名字符,但我的输入不会添加到现有字符串中,这些字符串应该是数据绑定的。它似乎擦除了数据绑定字符串并从头开始创建一个新字符串。
我做错了什么?
答案 0 :(得分:1)
为了能够在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);
}
}
}
答案 1 :(得分:1)
LoginPassword.Password = Globals.credentials == null ? "": new NetworkCredential("", Globals.credentials.SecurePassword).Password;
只需在xaml.cs文件中放入一行。将密码框命名为“ LoginPassword”。