UserControl中的PasswordBox - DataBinding有效,但框看起来是空的

时间:2017-02-04 00:01:26

标签: c# wpf xaml dependency-properties passwordbox

前期信息/问题: 下面发布的所有内容都可以工作(数据绑定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看起来是空的。如果我先在代码中设置密码并查看控件,它就不会显示已经输入的数据绑定文本的一堆匿名圆圈字符(但字符串本身是正确的 - 调试器说的是这样且实际的登录工作!)。如果我手动在框中输入密码文本,我会为我的条目获取匿名字符,但我的输入不会添加到现有字符串中,这些字符串应该是数据绑定的。它似乎擦除了数据绑定字符串并从头开始创建一个新字符串。

我做错了什么?

2 个答案:

答案 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”。