Skip to content

Commit ac77205

Browse files
authored
Merge pull request #36 from PHOENIXCONTACT/feature/passwordBoxHelper
Added PasswordBoxHelper to provide possibility to bind password in MVVM
2 parents 592d2b7 + f31303e commit ac77205

File tree

3 files changed

+109
-1
lines changed

3 files changed

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

0 commit comments

Comments
 (0)