Skip to content

Commit dcb9a82

Browse files
committed
Added PasswordBoxHelper to provide possibility to bind password in MVVM
1 parent 592d2b7 commit dcb9a82

File tree

3 files changed

+106
-1
lines changed

3 files changed

+106
-1
lines changed

Directory.build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project>
22
<PropertyGroup>
3-
<LangVersion>8.0</LangVersion>
3+
<LangVersion>9.0</LangVersion>
44
</PropertyGroup>
55

66
<PropertyGroup>

src/Moryx.WpfToolkit/Moryx.WpfToolkit.csproj.DotSettings

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ListView/@EntryIndexedValue">True</s:Boolean>
5757
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=multiprogressbar/@EntryIndexedValue">True</s:Boolean>
5858
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=localization/@EntryIndexedValue">True</s:Boolean>
59+
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=passwordbox/@EntryIndexedValue">True</s:Boolean>
5960
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ProgressBar/@EntryIndexedValue">True</s:Boolean>
6061
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=propertychanged/@EntryIndexedValue">True</s:Boolean>
6162
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=radiobutton/@EntryIndexedValue">True</s:Boolean>
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
using System.Windows;
2+
using System.Windows.Controls;
3+
4+
namespace Moryx.WpfToolkit
5+
{
6+
/// <summary>
7+
/// Helper class for the password box to bind the password
8+
/// </summary>
9+
public static class PasswordBoxHelper
10+
{
11+
/// <summary>
12+
/// Attached property for the bound password
13+
/// </summary>
14+
public static readonly DependencyProperty BoundPassword =
15+
DependencyProperty.RegisterAttached("BoundPassword", typeof(string), typeof(PasswordBoxHelper), new PropertyMetadata(string.Empty, OnBoundPasswordChanged));
16+
17+
/// <summary>
18+
/// Attached property for the bind password
19+
/// </summary>
20+
public static readonly DependencyProperty BindPassword = DependencyProperty.RegisterAttached(
21+
"BindPassword", typeof(bool), typeof(PasswordBoxHelper), new PropertyMetadata(false, OnBindPasswordChanged));
22+
23+
private static readonly DependencyProperty UpdatingPassword =
24+
DependencyProperty.RegisterAttached("UpdatingPassword", typeof(bool), typeof(PasswordBoxHelper), new PropertyMetadata(false));
25+
26+
/// <summary>
27+
/// Gets the <see cref="BindPassword"/> value
28+
/// </summary>
29+
public static bool GetBindPassword(DependencyObject dp) =>
30+
(bool)dp.GetValue(BindPassword);
31+
32+
/// <summary>
33+
/// Sets the <see cref="BindPassword"/> value
34+
/// </summary>
35+
public static void SetBindPassword(DependencyObject dp, bool value) =>
36+
dp.SetValue(BindPassword, value);
37+
38+
/// <summary>
39+
/// Gets the <see cref="BoundPassword"/> value
40+
/// </summary>
41+
public static string GetBoundPassword(DependencyObject dp) =>
42+
(string)dp.GetValue(BoundPassword);
43+
44+
/// <summary>
45+
/// Sets the <see cref="BoundPassword"/> value
46+
/// </summary>
47+
public static void SetBoundPassword(DependencyObject dp, string value) =>
48+
dp.SetValue(BoundPassword, value);
49+
50+
private static bool GetUpdatingPassword(DependencyObject dp) =>
51+
(bool)dp.GetValue(UpdatingPassword);
52+
53+
private static void SetUpdatingPassword(DependencyObject dp, bool value) =>
54+
dp.SetValue(UpdatingPassword, value);
55+
56+
private static void OnBoundPasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
57+
{
58+
var box = d as PasswordBox;
59+
60+
// only handle this event when the property is attached to a PasswordBox
61+
// and when the BindPassword attached property has been set to true
62+
if (d == null || !GetBindPassword(d))
63+
return;
64+
65+
// avoid recursive updating by ignoring the box's changed event
66+
box.PasswordChanged -= HandlePasswordChanged;
67+
68+
var newPassword = (string)e.NewValue;
69+
70+
if (!GetUpdatingPassword(box))
71+
box.Password = newPassword;
72+
73+
box.PasswordChanged += HandlePasswordChanged;
74+
}
75+
76+
private static void OnBindPasswordChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
77+
{
78+
// When the BindPassword attached property is set on a PasswordBox,
79+
// start listening to its PasswordChanged event
80+
if (dp is not PasswordBox box)
81+
return;
82+
83+
var wasBound = (bool)e.OldValue;
84+
var needToBind = (bool)e.NewValue;
85+
86+
if (wasBound)
87+
box.PasswordChanged -= HandlePasswordChanged;
88+
89+
if (needToBind)
90+
box.PasswordChanged += HandlePasswordChanged;
91+
}
92+
93+
private static void HandlePasswordChanged(object sender, RoutedEventArgs e)
94+
{
95+
var box = sender as PasswordBox;
96+
97+
// set a flag to indicate that we're updating the password
98+
SetUpdatingPassword(box, true);
99+
// push the new password into the BoundPassword property
100+
SetBoundPassword(box, box.Password);
101+
SetUpdatingPassword(box, false);
102+
}
103+
}
104+
}

0 commit comments

Comments
 (0)