How to bind to attached property in XAML, WPF

7.2k Views Asked by At

I would like to bind the User.Password property to PasswordBox (TwoWay). Since PasswordBox.Password is not bindable, I made AttachedProperties to fix this (one to activate the binding, and one to hold the actual password). The problem is that they won't bind (GetBindingExpression returns null).

Also:

  • The AttachedProperties work. The Password, and PasswordValue (attached prop) are set properly if I type into the PasswordBox, but User.Password remains empty.
  • Binding the AttachedProperty also works, but only the other way around: if I bind PasswordValue to a TextBlock (TextBlock.Text is the target, helper:PasswordValue is the source) it works. Only I can't use this, because properties of User are not dependency objects.
  • The User.Password is bindable (User implements INotifyPropertyChanged), and I managed to bind User.Username to a TextBox.Text and (Username and Password are similar string properties)

Here are the AttachedProperties:

public static bool GetTurnOnBinding(DependencyObject obj)
        {
            return (bool)obj.GetValue(TurnOnBindingProperty);
        }

        public static void SetTurnOnBinding(DependencyObject obj, bool value)
        {
            obj.SetValue(TurnOnBindingProperty, value);
        }

        // Using a DependencyProperty as the backing store for TurnOnBinding. This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TurnOnBindingProperty =
            DependencyProperty.RegisterAttached(
            "TurnOnBinding",
            typeof(bool),
            typeof(PasswordHelper),
            new UIPropertyMetadata(false, (d, e) =>
            {
                var pb = d as PasswordBox;
                SetPasswordValue(pb, pb.Password);
                pb.PasswordChanged += (s, x) => SetPasswordValue(pb, pb.Password);
            }));

        public static string GetPasswordValue(DependencyObject obj)
        {
            return (string)obj.GetValue(PasswordValueProperty);
        }

        public static void SetPasswordValue(DependencyObject obj, string value)
        {
            obj.SetValue(PasswordValueProperty, value);
        }

        // Using a DependencyProperty as the backing store for PasswordValue.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PasswordValueProperty =
            DependencyProperty.RegisterAttached(
            "PasswordValue",
            typeof(string),
            typeof(PasswordHelper), new UIPropertyMetadata(null, (d, e) =>
            {
                PasswordBox p = d as PasswordBox;
                string s = e.NewValue as string;

                if (p.Password != s) p.Password = s;
            }));

And the XAML part with the binding:

<PasswordBox x:Name="passBox" 
    root:PasswordHelper.TurnOnBinding="True" 
    root:PasswordHelper.PasswordValue="{Binding Text, 
        ElementName=passSupport, Mode=TwoWay}"/>
2

There are 2 best solutions below

0
On BEST ANSWER

Sorry to say, I can't say what's wrong with your code (IMHO it should work), but since I had a similiar problem in Silverlight, and the designer doesn't really like binding to and from attached properties, I've found they aren't worth the hassle.
My current preferred method of extending controls' behavior is using the System.Windows.Interactivity.Behavior base class (see here and here) and then attaching my behaviors to the controls.

So, you'd need a class PasswordBehavior : Behavior<PasswordBox>, which overrides OnAttached(), and subscribes to the passwordBox's PasswordChanged event, and has a bindable DependencyProperty called PasswordValue. In the event handler change the dp's value, and on the dp's callback change the control's Password value.

0
On

Check out PasswordBoxAssistant. Just change the properties BoundPassword => BoundPasswordProperty, BindPassword => BindPasswordProperty, UpdatingPassword => UpdatingPasswordProperty to avoid warnings in XAML view.