Use PasswordBoxes in Stylet.Samples.ModelValidation

This commit is contained in:
Antony Male 2014-05-14 12:11:49 +01:00
parent 6b2c8d9583
commit ba8d5f338c
4 changed files with 121 additions and 6 deletions

View File

@ -24,13 +24,18 @@ namespace Stylet.Samples.ModelValidation
public async Task<string[]> ValidatePropertyAsync(string propertyName)
{
return (await this.validator.ValidateAsync(this.subject, propertyName)).Errors.Select(x => x.ErrorMessage).ToArray();
// If someone's calling us synchronously, and ValidationAsync does not complete synchronously,
// we'll deadlock unless we continue on another thread.
return (await this.validator.ValidateAsync(this.subject, propertyName).ConfigureAwait(false))
.Errors.Select(x => x.ErrorMessage).ToArray();
}
public async Task<Dictionary<string, string[]>> ValidateAllPropertiesAsync()
{
return (await this.validator.ValidateAsync(this.subject)).Errors
.GroupBy(x => x.PropertyName)
// If someone's calling us synchronously, and ValidationAsync does not complete synchronously,
// we'll deadlock unless we continue on another thread.
return (await this.validator.ValidateAsync(this.subject).ConfigureAwait(false))
.Errors.GroupBy(x => x.PropertyName)
.ToDictionary(x => x.Key, x => x.Select(failure => failure.ErrorMessage).ToArray());
}
}

View File

@ -4,6 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:xaml="clr-namespace:Stylet.Samples.ModelValidation.Xaml"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
@ -11,7 +12,7 @@
<Setter Property="Margin" Value="5,0,5,0" />
<Setter Property="HorizontalAlignment" Value="Left" />
</Style>
<Style TargetType="{x:Type TextBox}">
<Style x:Key="CommonStyle" TargetType="{x:Type Control}">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Margin" Value="0,2,40,20" />
<Setter Property="Validation.ErrorTemplate">
@ -33,6 +34,8 @@
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource CommonStyle}"/>
<Style TargetType="{x:Type PasswordBox}" BasedOn="{StaticResource CommonStyle}"/>
</UserControl.Resources>
<Grid Margin="10">
@ -55,10 +58,10 @@
<TextBox Grid.Row="1" Grid.Column="1" x:Name="Email" Text="{Binding Email}"/>
<Label Grid.Row="2" Grid.Column="0" Target="{Binding ElementName=Password}">Password:</Label>
<TextBox Grid.Row="2" Grid.Column="1" x:Name="Password" Text="{Binding Password}"/>
<PasswordBox Grid.Row="2" Grid.Column="1" x:Name="Password" xaml:Secure.Password="{Binding Password}"/>
<Label Grid.Row="3" Grid.Column="0" Target="{Binding ElementName=PasswordConfirmation}">Password Confirmation:</Label>
<TextBox Grid.Row="3" Grid.Column="1" x:Name="PasswordConfirmation" Text="{Binding PasswordConfirmation}"/>
<PasswordBox Grid.Row="3" Grid.Column="1" x:Name="PasswordConfirmation" xaml:Secure.Password="{Binding PasswordConfirmation}"/>
<CheckBox Grid.Row="4" Grid.Column="0" IsChecked="{Binding AutoValidate}">Auto-Validate</CheckBox>
<Button Grid.Row="4" Grid.Column="1" Command="{s:Action Submit}" HorizontalAlignment="Left">Submit</Button>

View File

@ -67,6 +67,7 @@
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Xaml\Secure.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="Bootstrapper.cs" />

View File

@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace Stylet.Samples.ModelValidation.Xaml
{
public static class Secure
{
private static bool passwordInitialized;
private static bool settingPassword;
public static string GetPassword(DependencyObject obj)
{
return (string)obj.GetValue(PasswordProperty);
}
public static void SetPassword(DependencyObject obj, string value)
{
obj.SetValue(PasswordProperty, value);
}
// Using a DependencyProperty as the backing store for Password. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PasswordProperty =
DependencyProperty.RegisterAttached("Password", typeof(string), typeof(Secure), new FrameworkPropertyMetadata(String.Empty, HandleBoundPasswordChanged)
{
BindsTwoWayByDefault = true,
DefaultUpdateSourceTrigger = UpdateSourceTrigger.LostFocus // Match the default on Binding
});
private static void HandleBoundPasswordChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
{
if (settingPassword)
return;
var passwordBox = dp as PasswordBox;
if (passwordBox == null)
return;
// If this is the initial set
if (!passwordInitialized)
{
passwordInitialized = true;
passwordBox.PasswordChanged += HandlePasswordChanged;
}
passwordBox.Password = e.NewValue as string;
}
private static void HandlePasswordChanged(object sender, RoutedEventArgs e)
{
var passwordBox = (PasswordBox)sender;
settingPassword = true;
SetPassword(passwordBox, passwordBox.Password);
settingPassword = false;
}
private static bool securePasswordInitialized;
private static bool settingSecurePassword;
public static SecureString GetSecurePassword(DependencyObject obj)
{
return (SecureString)obj.GetValue(SecurePasswordProperty);
}
public static void SetSecurePassword(DependencyObject obj, SecureString value)
{
obj.SetValue(SecurePasswordProperty, value);
}
public static readonly DependencyProperty SecurePasswordProperty =
DependencyProperty.RegisterAttached("SecurePassword", typeof(SecureString), typeof(Secure), new FrameworkPropertyMetadata(new SecureString(), HandleBoundSecurePasswordChanged) { BindsTwoWayByDefault = true });
private static void HandleBoundSecurePasswordChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
{
if (settingSecurePassword)
return;
var passwordBox = dp as PasswordBox;
if (passwordBox == null)
return;
if (!securePasswordInitialized)
{
passwordBox.PasswordChanged += HandleSecurePasswordChanged;
securePasswordInitialized = true;
}
}
private static void HandleSecurePasswordChanged(object sender, RoutedEventArgs e)
{
var passwordBox = (PasswordBox)sender;
settingSecurePassword = true;
SetSecurePassword(passwordBox, passwordBox.SecurePassword);
settingSecurePassword = false;
}
}
}