Skip to content

Instantly share code, notes, and snippets.

@cbalioglu
Last active June 13, 2024 11:49
Show Gist options
  • Save cbalioglu/64dda0744ea63bd7d8dc to your computer and use it in GitHub Desktop.
Save cbalioglu/64dda0744ea63bd7d8dc to your computer and use it in GitHub Desktop.
An Expression Blend behavior for WPF that enables binding to the Password property of the PasswordBox control.
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Interactivity;
namespace Balioglu
{
// USAGE:
//
//<PasswordBox>
// <blend:Interaction.Behaviors>
// <l:PasswordBoxBehavior UpdateSourceTrigger="PropertyChanged"
// Binding="{Binding Source={StaticResource MyViewModel},Path=Password}" />
// </blend:Interaction.Behaviors>
//</PasswordBox>
//
/// <summary>
/// Enables binding to the <see cref="Password" /> property of the <see cref="PasswordBox" /> control.
/// </summary>
/// <remarks>
/// Note that storing plain text passwords in memory is a security risk. You should avoid using this solution
/// unless it is absolutely necessary to use the MVVM pattern.
/// </remarks>
public sealed class PasswordBoxBehavior : Behavior<PasswordBox>
{
public static readonly DependencyProperty BindingProperty =
DependencyProperty.Register("Binding", typeof(String), typeof(PasswordBoxBehavior),
new FrameworkPropertyMetadata(OnBindingChanged) { BindsTwoWayByDefault = true });
public static readonly DependencyProperty UpdateSourceTriggerProperty =
DependencyProperty.Register("UpdateSourceTrigger", typeof(UpdateSourceTrigger), typeof(PasswordBoxBehavior),
new PropertyMetadata(UpdateSourceTrigger.LostFocus), ValidateUpdateSourceTrigger);
/// <summary>
/// Gets or sets the password.
/// </summary>
public String Binding
{
get
{
return (String) GetValue(BindingProperty);
}
set
{
SetValue(BindingProperty, value);
}
}
/// <summary>
/// Gets or sets the timing of binding source updates.
/// </summary>
public UpdateSourceTrigger UpdateSourceTrigger
{
get
{
return (UpdateSourceTrigger) GetValue(UpdateSourceTriggerProperty);
}
set
{
SetValue(UpdateSourceTriggerProperty, value);
}
}
private static void OnBindingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
PasswordBoxBehavior behavior = d as PasswordBoxBehavior;
if (behavior != null)
{
behavior.SetTargetPassword((String) e.NewValue);
}
}
private static Boolean ValidateUpdateSourceTrigger(Object value)
{
UpdateSourceTrigger trigger = (UpdateSourceTrigger) value;
return
trigger == UpdateSourceTrigger.Default ||
trigger == UpdateSourceTrigger.LostFocus ||
trigger == UpdateSourceTrigger.PropertyChanged;
}
private Boolean m_passwordBoxChanged;
private Boolean m_isUpdatingBinding;
protected override void OnAttached()
{
base.OnAttached();
PasswordBox passwordBox = AssociatedObject;
passwordBox.PasswordChanged += OnPasswordBoxChanged;
passwordBox.LostFocus += OnPasswordBoxLostFocus;
passwordBox.SetBinding(Validation.ValidationAdornerSiteForProperty, new Binding { Source = this });
}
protected override void OnDetaching()
{
base.OnDetaching();
PasswordBox passwordBox = AssociatedObject;
passwordBox.PasswordChanged -= OnPasswordBoxChanged;
passwordBox.LostFocus -= OnPasswordBoxLostFocus;
BindingOperations.ClearBinding(passwordBox, Validation.ValidationAdornerSiteForProperty);
}
private void SetTargetPassword(String password)
{
if (m_isUpdatingBinding)
{
return;
}
PasswordBox passwordBox = AssociatedObject;
passwordBox.PasswordChanged -= OnPasswordBoxChanged;
passwordBox.Password = password;
passwordBox.PasswordChanged += OnPasswordBoxChanged;
}
private void OnPasswordBoxChanged(Object sender, RoutedEventArgs e)
{
if (UpdateSourceTrigger == UpdateSourceTrigger.PropertyChanged)
{
UpdateBinding();
}
else
{
m_passwordBoxChanged = true;
}
}
private void OnPasswordBoxLostFocus(Object sender, RoutedEventArgs e)
{
if (UpdateSourceTrigger == UpdateSourceTrigger.PropertyChanged || !m_passwordBoxChanged)
{
return;
}
UpdateBinding();
m_passwordBoxChanged = false;
}
private void UpdateBinding()
{
m_isUpdatingBinding = true;
Binding = AssociatedObject.Password;
m_isUpdatingBinding = false;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment