namespace SpeedportHybridControl.Implementations {
- // see http://antonymale.co.uk/2015/08/binding-to-a-passwordbox-password-in-wpf
+ // http://blog.functionalfun.net/2008/06/wpf-passwordbox-and-data-binding.html
public static class PasswordHelper {
- private static readonly DependencyProperty PasswordInitializedProperty =
- DependencyProperty.RegisterAttached("PasswordInitialized", typeof(bool), typeof(PasswordHelper), new PropertyMetadata(false));
-
- private static readonly DependencyProperty SettingPasswordProperty =
- DependencyProperty.RegisterAttached("SettingPassword", typeof(bool), typeof(PasswordHelper), new PropertyMetadata(false));
-
- public static string GetPassword (DependencyObject obj) {
- return (string)obj.GetValue(PasswordProperty);
- }
- public static void SetPassword (DependencyObject obj, string value) {
- obj.SetValue(PasswordProperty, value);
- }
- // We play a trick here. If we set the initial value to something, it'll be set to something else when the binding kicks in,
- // and HandleBoundPasswordChanged will be called, which allows us to set up our event subscription.
- // If the binding sets us to a value which we already are, then this doesn't happen. Therefore start with a value that's
- // definitely unique.
- public static readonly DependencyProperty PasswordProperty =
- DependencyProperty.RegisterAttached("Password", typeof(string), typeof(PasswordHelper),
- new FrameworkPropertyMetadata(Guid.NewGuid().ToString(), HandleBoundPasswordChanged) {
- BindsTwoWayByDefault = true,
- DefaultUpdateSourceTrigger = UpdateSourceTrigger.LostFocus // Match the default on Binding
- });
-
- private static void HandleBoundPasswordChanged (DependencyObject dp, DependencyPropertyChangedEventArgs e) {
- var passwordBox = dp as PasswordBox;
- if (passwordBox == null)
+ public static readonly DependencyProperty BoundPassword =
+ DependencyProperty.RegisterAttached("BoundPassword", typeof(string), typeof(PasswordHelper), new PropertyMetadata(string.Empty, OnBoundPasswordChanged));
+
+ public static readonly DependencyProperty BindPassword = DependencyProperty.RegisterAttached(
+ "BindPassword", typeof(bool), typeof(PasswordHelper), new PropertyMetadata(false, OnBindPasswordChanged));
+
+ private static readonly DependencyProperty UpdatingPassword =
+ DependencyProperty.RegisterAttached("UpdatingPassword", typeof(bool), typeof(PasswordHelper), new PropertyMetadata(false));
+
+ private static void OnBoundPasswordChanged (DependencyObject d, DependencyPropertyChangedEventArgs e) {
+ PasswordBox box = d as PasswordBox;
+
+ // only handle this event when the property is attached to a PasswordBox
+ // and when the BindPassword attached property has been set to true
+ if (d == null || !GetBindPassword(d)) {
return;
+ }
+
+ // avoid recursive updating by ignoring the box's changed event
+ box.PasswordChanged -= HandlePasswordChanged;
- // If we're being called because we set the value of the property we're bound to (from inside
- // HandlePasswordChanged, then do nothing - we already have the latest value).
- if ((bool)passwordBox.GetValue(SettingPasswordProperty))
+ string newPassword = (string)e.NewValue;
+
+ if (!GetUpdatingPassword(box)) {
+ box.Password = newPassword;
+ }
+
+ box.PasswordChanged += HandlePasswordChanged;
+ }
+
+ private static void OnBindPasswordChanged (DependencyObject dp, DependencyPropertyChangedEventArgs e) {
+ // when the BindPassword attached property is set on a PasswordBox,
+ // start listening to its PasswordChanged event
+
+ PasswordBox box = dp as PasswordBox;
+
+ if (box == null) {
return;
+ }
+
+ bool wasBound = (bool)(e.OldValue);
+ bool needToBind = (bool)(e.NewValue);
- // If this is the initial set (see the comment on PasswordProperty), set ourselves up
- if (!(bool)passwordBox.GetValue(PasswordInitializedProperty)) {
- passwordBox.SetValue(PasswordInitializedProperty, true);
- passwordBox.PasswordChanged += HandlePasswordChanged;
+ if (wasBound) {
+ box.PasswordChanged -= HandlePasswordChanged;
}
- passwordBox.Password = e.NewValue as string;
+ if (needToBind) {
+ box.PasswordChanged += HandlePasswordChanged;
+ }
}
private static void HandlePasswordChanged (object sender, RoutedEventArgs e) {
- var passwordBox = (PasswordBox)sender;
- passwordBox.SetValue(SettingPasswordProperty, true);
- SetPassword(passwordBox, passwordBox.Password);
- passwordBox.SetValue(SettingPasswordProperty, false);
+ PasswordBox box = sender as PasswordBox;
+
+ // set a flag to indicate that we're updating the password
+ SetUpdatingPassword(box, true);
+ // push the new password into the BoundPassword property
+ SetBoundPassword(box, box.Password);
+ SetUpdatingPassword(box, false);
+ }
+
+ public static void SetBindPassword (DependencyObject dp, bool value) {
+ dp.SetValue(BindPassword, value);
+ }
+
+ public static bool GetBindPassword (DependencyObject dp) {
+ return (bool)dp.GetValue(BindPassword);
+ }
+
+ public static string GetBoundPassword (DependencyObject dp) {
+ return (string)dp.GetValue(BoundPassword);
+ }
+
+ public static void SetBoundPassword (DependencyObject dp, string value) {
+ dp.SetValue(BoundPassword, value);
+ }
+
+ private static bool GetUpdatingPassword (DependencyObject dp) {
+ return (bool)dp.GetValue(UpdatingPassword);
+ }
+
+ private static void SetUpdatingPassword (DependencyObject dp, bool value) {
+ dp.SetValue(UpdatingPassword, value);
}
}
}
<TextBox Text="{Binding Path=ip, Mode=TwoWay}" HorizontalAlignment="Left" Height="23" Margin="115,14,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<TextBlock Text="Passwort:" HorizontalAlignment="Left" Margin="55,49,0,0" VerticalAlignment="Top" />
- <PasswordBox Implementations:PasswordHelper.Password="{Binding Path=password, Mode=TwoWay, NotifyOnSourceUpdated=True}" Visibility="{Binding Path=PasswordBoxVisibility}" x:Name="passwordBox" HorizontalAlignment="Left" Height="23" Margin="115,42,0,0" VerticalAlignment="Top" Width="120" ForceCursor="True" />
+ <PasswordBox Implementations:PasswordHelper.BindPassword="true" Implementations:PasswordHelper.BoundPassword="{Binding Path=password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding Path=PasswordBoxVisibility}" x:Name="passwordBox" HorizontalAlignment="Left" Height="23" Margin="115,42,0,0" VerticalAlignment="Top" Width="120" ForceCursor="True" />
<TextBox Text="{Binding Path=password, Mode=TwoWay}" HorizontalAlignment="Left" Height="23" Margin="115,42,0,0" VerticalAlignment="Top" Width="120" Visibility="{Binding Path=PasswordTextBoxVisibility}"/>
<CheckBox Command="{Binding Path=ShowPasswordCommand}" IsChecked="{Binding Path=ShowPassword, Mode=TwoWay}" Content="Passwort anzeigen" Margin="240,50,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" />
<CheckBox Command="{Binding Path=SavePasswordCommand}" IsChecked="{Binding Path=SavePassword, Mode=TwoWay}" Content="Passwort speichern" Margin="240,65,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" />