我有一个WPF表单,其中包含以下控件 -
名称 - 文本框
密码 - PasswordBox
确认密码 - PasswordBox
保存 - 按钮
需要的是 - 仅当所有控件都具有有效值
时才启用保存按钮名称不应为空 - 要验证这一点,我使用的是自定义ValidationRule
密码不应为空 - 要验证这一点,我使用的是自定义ValidationRule
密码和确认密码应匹配。
我正在使用ValidationRule,因为它在发生错误时不会更新源代码。 [我不能使用IDataInfoError]。
我无法验证密码和确认密码匹配条件。下面是我的XAML和代码背后 -
<Window x:Class="WPFPasswordValidation.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPFPasswordValidation"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ResourceDictionary>
<ControlTemplate x:Key="validationTemplate">
<DockPanel>
<Border BorderBrush="Red" BorderThickness="1">
<AdornedElementPlaceholder/>
</Border>
</DockPanel>
</ControlTemplate>
<Style x:Key="textBoxInError" TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="passwordBoxInError" TargetType="{x:Type PasswordBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
</Window.Resources>
<Grid>
<TextBox Name="txtName" HorizontalAlignment="Left" Height="23" Margin="155,31,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" Validation.Error="Validation_Error" Style="{StaticResource textBoxInError}" Validation.ErrorTemplate="{StaticResource validationTemplate}">
<TextBox.Text>
<Binding Path="Name" UpdateSourceTrigger="Explicit" NotifyOnValidationError="true" Mode="TwoWay">
<Binding.ValidationRules>
<local:StringRangeValidationRule MinimumLength="1" MaximumLength="30"
ErrorMessage="Name is required and must be less than 30 letters."/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<PasswordBox HorizontalAlignment="Left" Margin="155,128,0,0" VerticalAlignment="Top" Width="120" Name="txtConfirmPass"/>
<TextBlock HorizontalAlignment="Left" Margin="106,35,0,0" TextWrapping="Wrap" VerticalAlignment="Top"><Run Text="Name"/></TextBlock>
<PasswordBox Name="txtPassword" HorizontalAlignment="Left" Margin="155,85,0,0" VerticalAlignment="Top" Width="120" PasswordChar="*" local:PasswordBoxAssistant.BindPassword="true" Validation.Error="Validation_Error" Style="{StaticResource passwordBoxInError}" Validation.ErrorTemplate="{StaticResource validationTemplate}">
<local:PasswordBoxAssistant.BoundPassword>
<Binding Path="Password" Mode="TwoWay" UpdateSourceTrigger="Explicit" NotifyOnValidationError="true">
<Binding.ValidationRules>
<local:StringRangeValidationRule MinimumLength="1" MaximumLength="30"
ErrorMessage="Password is required and must be less than 30 letters."/>
</Binding.ValidationRules>
</Binding>
</local:PasswordBoxAssistant.BoundPassword>
</PasswordBox>
<TextBlock HorizontalAlignment="Left" Margin="88,85,0,0" TextWrapping="Wrap" Text="Password" VerticalAlignment="Top"/>
<TextBlock HorizontalAlignment="Left" Margin="42,128,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Height="20"><Run Text="Confirm Password"/></TextBlock>
<Button Content="Save" HorizontalAlignment="Left" Margin="169,186,0,0" VerticalAlignment="Top" Width="75" Command="Save">
<Button.CommandBindings>
<CommandBinding Command="Save" Executed="Save_Executed" CanExecute="Save_CanExecute"/>
</Button.CommandBindings>
</Button>
</Grid>
C#背后的代码 -
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Globalization;
namespace WPFPasswordValidation
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private int _noOfErrors = 0;
BindingExpression be = null;
public MainWindow()
{
InitializeComponent();
Person p = new Person();
p.Name = "abc";
p.Password = "1234";
this.DataContext = p;
}
private void Validation_Error(object sender, ValidationErrorEventArgs e)
{
if (e.Action == ValidationErrorEventAction.Added)
_noOfErrors++;
else
_noOfErrors--;
}
private void Save_Executed(object sender, ExecutedRoutedEventArgs e)
{
}
private void Save_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
be = this.txtName.GetBindingExpression(TextBox.TextProperty);
be.UpdateSource();
be = this.txtPassword.GetBindingExpression(PasswordBoxAssistant.BoundPassword);
be.UpdateSource();
e.CanExecute = _noOfErrors == 0;
e.Handled = true;
}
}
public class StringRangeValidationRule : ValidationRule
{
private int _minimumLength = -1;
private int _maximumLength = -1;
private string _errorMessage;
public int MinimumLength
{
get { return _minimumLength; }
set { _minimumLength = value; }
}
public int MaximumLength
{
get { return _maximumLength; }
set { _maximumLength = value; }
}
public string ErrorMessage
{
get { return _errorMessage; }
set { _errorMessage = value; }
}
public override ValidationResult Validate(object value,
CultureInfo cultureInfo)
{
ValidationResult result = new ValidationResult(true, null);
string inputString = (value ?? string.Empty).ToString();
if (inputString == null)
{
inputString = string.Empty;
}
if (inputString.Length < this.MinimumLength ||
(this.MaximumLength > 0 &&
inputString.Length > this.MaximumLength))
{
result = new ValidationResult(false, this.ErrorMessage);
}
return result;
}
}
public static class PasswordBoxAssistant
{
public static readonly DependencyProperty BoundPassword =
DependencyProperty.RegisterAttached("BoundPassword", typeof(string), typeof(PasswordBoxAssistant), new PropertyMetadata(string.Empty, OnBoundPasswordChanged));
public static readonly DependencyProperty BindPassword = DependencyProperty.RegisterAttached(
"BindPassword", typeof(bool), typeof(PasswordBoxAssistant), new PropertyMetadata(false, OnBindPasswordChanged));
private static readonly DependencyProperty UpdatingPassword =
DependencyProperty.RegisterAttached("UpdatingPassword", typeof(bool), typeof(PasswordBoxAssistant), 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;
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 (wasBound)
{
box.PasswordChanged -= HandlePasswordChanged;
}
if (needToBind)
{
box.PasswordChanged += HandlePasswordChanged;
}
}
private static void HandlePasswordChanged(object sender, RoutedEventArgs e)
{
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);
}
}
public class Person
{
private string _name;
private string _password;
public string Password
{
get { return _password; }
set { _password = value; }
}
public string Name
{
get { return _name; }
set
{
_name = value;
}
}
}
}
答案 0 :(得分:1)
也许你可以用事件验证那些阵营
<Grid>
<TextBox Name="txtName" TextChanged="Content_TextChanged"/>
<PasswordBox Name="txtPass" PasswordChar="*" PasswordChanged="Content_TextChanged"/>
<PasswordBox Name="txtConfirmPass" PasswordChar="*" PasswordChanged="Content_TextChanged"/>
<Button Name="btSave" Content="Save" IsEnabled="False"/>
</Grid>
事件:
private void Content_TextChanged(object sender, TextChangedEventArgs e)
{
if (!txtName.Text.Equals(String.Empty) && txtPass.Password.Equals(txtConfirmPass.Password))
btSave.IsEnabled = true;
else
btSave.IsEnabled = false;
}
答案 1 :(得分:1)
if (txtpassword1.Text == "" || txtpassword2.Text == "")
{
MessageBox.Show("Please enter values");
txtpassword1.Focus();
return;
}
else if (txtpassword1.Text != txtpassword2.Text)
{
MessageBox.Show("Password not matching");
txtpassword2.Focus();
return;
}
答案 2 :(得分:0)
由于我不是ValidationRule
的粉丝,我无法直接回答你的问题,但我只是想告诉你有一个很多更简单的方法来做到这一点
private void Save_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
Person person = (Person)DataContext;
e.CanExecute = !string.IsNullOrEmpty(person.Name) &&
!string.IsNullOrEmpty(person.Password) &&
!string.IsNullOrEmpty(txtConfirmPass.Text) &&
txtConfirmPass.Text == person.Password;
}
如果在出现错误时确实需要控件上的红色边框,那么您可以在数据类型类上实现IDataErrorInfo
接口,例如。 Person
。