Search code examples
c#wpfdata-bindingworkflow-foundation-4propertygrid

Password/Mask field in WPF PropertyGrid is not persisted


I'm trying to build a password (masked) field for a WPF PropertyGrid that's used in a WF re-hoster designer solution. Note that I'm not interested in the security element of it. I just want the password hidden from the user. I really struggled with something I would have thought would have been simple to implemented but I eventually found this great article which really helped:

WPF PasswordBox and Data binding

After creating the PasswordBoxAssistant class as per article, I created a WPF UserControl with the following XAML and Code:

XAML

<Grid>
    <PasswordBox x:Name="PasswordBox"
                 Background="Green" 
                 local:PasswordBoxAssistant.BindPassword="true" 
                 local:PasswordBoxAssistant.BoundPassword="{Binding Password,
                 Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>

Code-Behind:

public partial class PasswordUserControl : UserControl
{
    public PasswordUserControl()
    {
        InitializeComponent();
    }

    public static readonly DependencyProperty PasswordProperty = 
      DependencyProperty.Register("Password",
      typeof(string), typeof(PasswordUserControl),
      new FrameworkPropertyMetadata(PasswordChanged));

    public string Password
    {
        get
        {
            return (string)GetValue(PasswordProperty);
        }
        set
        {
            SetValue(PasswordProperty, value);
        }
    }

    private static void PasswordChanged(DependencyObject source, 
       DependencyPropertyChangedEventArgs e)
    {
        if (e.NewValue != null)
        {
            (source as PasswordUserControl)?.UpdatePassword(e.NewValue.ToString());
        }
        else
        {
            (source as PasswordUserControl)?.UpdatePassword(string.Empty);
        }
    }

    private void UpdatePassword(string newText)
    {
        PasswordBox.Password = Password;
    }
}

Then I created a PropertyValueEditor class (called PasswordEditor.cs) and I'm assuming this is the part that's not working and I'm not setting correctly.

I'm binding the PasswordProperty from the UserControl to the Value field of the PropertyValueEditor.

public class PasswordEditor : PropertyValueEditor
{
    public PasswordEditor()
    {
        this.InlineEditorTemplate = new DataTemplate();
        FrameworkElementFactory stack = new FrameworkElementFactory(typeof(StackPanel));
        FrameworkElementFactory passwordBox = new 
                    FrameworkElementFactory(typeof(PasswordUserControl));
        Binding passwordBoxBinding = new Binding("Value") { Mode = BindingMode.TwoWay };
        passwordBox.SetValue(PasswordUserControl.PasswordProperty, passwordBoxBinding);
        stack.AppendChild(passwordBox);
        this.InlineEditorTemplate.VisualTree = stack;
    }
}

I've tried to set it to the StringValue as well as per other WF PropertyValueEditor samples I have found but to no avail.

The password (masked) field is now displaying correctly in my WPF PropertyGrid, but it's not persisting the value when I switch to another WF activity and switch back to the one that contains the password field.

Can anyone point me in the right direction?

Thanks.

Again, any help would be appreciated.

Thanks.


Solution

  • I eventually figured out!!

    To resolve the persistence problem:

    The first thing I changed was in the XAML code, I changed the binded Password property to Value:

    <Grid>
        <PasswordBox x:Name="PasswordBox"
                     Background="Green" 
                     local:PasswordBoxAssistant.BindPassword="true" 
                     local:PasswordBoxAssistant.BoundPassword="{Binding Value, Mode=TwoWay, 
                     UpdateSourceTrigger=PropertyChanged}"/>
    </Grid>
    

    The second thing I changed was in the PasswordEditor where I was calling SetValue instead of SetBinding, so this was changed to:

    passwordBox.SetBinding(PasswordUserControl.PasswordProperty, 
                           passwordBoxBinding);
    

    Now the remaining weird problem is that when I type characters in the PasswordBox contained in the PasswordUserControl, it somehow always places the cursor in the first position which a) is really weird and looks wrong and b) it causes the password to be backward, so if I type 'Hello', it will be 'olleH'.

    I know to work-around it and move on, I could simply reverse the string every time, but having the cursor staying at the front of the textbox is just too weird for my taste, so I'd really like to figure out what's causing this.

    To resolve the cursor position and reversed string problem:

    I changed the PasswordChanged event in the PasswordUserControl:

        private static void PasswordChanged(DependencyObject source,
          DependencyPropertyChangedEventArgs e)
        {
            var passwordUserControl = source as PasswordUserControl;
    
            if (passwordUserControl != null)
                if (e.NewValue != null) passwordUserControl.Password =
                    e.NewValue.ToString();
        }
    

    Hope this helps