作者:只属于我一个人的秘密 | 来源:互联网 | 2023-09-23 12:40
表单的数据验证往往枯燥无味,又不可避免.
在一个如下表单只有两个输入框,和确定按钮的情况下,正常我们需要做哪些工作呢?
1. 如果年龄输入框输入了非数字的字符串,输入框失去焦点后,后面错误消息应当能立即提示出来
2.错误的提示的内容如果变化,你可能需要修改整个UI设计.(如显示在输入框下方)
3.点击OK按钮,需要遍历Window所有输入框,如果有输入数据验证不符合,需要提示错误,并将对应的控件获取焦点.
这很容易么?当这个输入框再多一些呢?
下面的Demo,看在WPF如何轻松处理这些:
Window里,textBox1,textBox2,textBox3 绑定的数据为:
class MyDataSource
{
private int _age;
private int _age2;
private int _age3;
public MyDataSource()
{
Age = 0;
Age2 = 0;
}
public int Age
{
get {
return _age; }
set { _age =
value; }
}
public int Age2
{
get {
return _age2; }
set { _age2 =
value; }
}
public int Age3
{
get {
return _age3; }
set { _age3 =
value; }
}
}
<TextBox Name="textBox1" Width="50" FontSize="15"
Validation.ErrorTemplate="{StaticResource validationTemplate}"
Style="{StaticResource textBoxInError}"
Grid.Row="1" Grid.Column="1" Margin="2">
<TextBox.Text>
<Binding Path="Age" Source="{StaticResource ods}"
UpdateSourceTrigger="PropertyChanged" >
<Binding.ValidationRules>
<c:AgeRangeRule Min="21" Max="130"/>
Binding.ValidationRules>
Binding>
TextBox.Text>
TextBox>
textBox1 绑定了Age ,并且使用的验证的规则为 AgeRangeRule ,规则中指定了最小值和最大值,当PropertyChanged时验证规则将触发,也就是该控件失去焦点之时. 提示的信息样式定义在ErrorTemplate里,让我们再来看一看ErrroTemplate的内容:
<ControlTemplate x:Key="validationTemplate">
<DockPanel>
<TextBlock Foreground="Red" FontSize="20">!TextBlock>
<AdornedElementPlaceholder/>
DockPanel>
ControlTemplate>
AdornedElementPlaceholder 才是这里的点睛之处,此处放置了待验证的控件,而整个ErrorTemplate正是使用神奇的Adoner实现了错误的提示的位置和原排版布局的无关性. 验证规则和整个代码完全解耦:
class AgeRangeRule : ValidationRule
{
private int _min;
private int _max;
public AgeRangeRule()
{
}
public int Min
{
get {
return _min; }
set { _min =
value; }
}
public int Max
{
get {
return _max; }
set { _max =
value; }
}
public override ValidationResult Validate(
object value, CultureInfo cultureInfo)
{
int age = 0;
try
{
if (((
string)
value).Length > 0)
age = Int32.Parse((String)
value);
}
catch (Exception e)
{
return new ValidationResult(
false, "
Illegal characters or " + e.Message);
}
if ((age
Max))
{
return new ValidationResult(false,
"Please enter an age in the range: " + Min + " - " + Max + ".");
}
else
{
return new ValidationResult(true, null);
}
}
}
验证规则验证失败时候抛出的异常显示在Tip里.
<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>
- 使用ExceptionValidationRule
另一种方法,不自定义Rule,如:
<TextBox Name="textBox3" Width="50" FontSize="15"
Grid.Row="5" Grid.Column="1" Margin="2"
Validation.ErrorTemplate="{StaticResource validationTemplate}"
Style="{StaticResource textBoxInError}">
<TextBox.Text>
<Binding Path="Age3" Source="{StaticResource ods}"
UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<ExceptionValidationRule/>
Binding.ValidationRules>
Binding>
TextBox.Text>
TextBox>
在后台代码中:
BindingExpression myBindingExpression = textBox3.GetBindingExpression(TextBox.TextProperty);
Binding myBinding = myBindingExpression.ParentBinding;
myBinding.UpdateSourceExceptiOnFilter= new UpdateSourceExceptionFilterCallback(ReturnExceptionHandler);
myBindingExpression.UpdateSource();
因为Age3 是Int类型,在textBox3 输入非int类型,将会引发异常,此时使用Rule的正是系统的ExceptionValidationRule,同样错误信息的模块不变.
-
验证所有控件
// Validate all dependency objects in a window
bool IsValid(DependencyObject node)
{
// Check if dependency object was passed
if (node !=
null)
{
// Check if dependency object is valid.
// NOTE: Validation.GetHasError works for controls that have validation rules attached
bool isValid = !Validation.GetHasError(node);
if (!isValid)
{
// If the dependency object is invalid, and it can receive the focus,
// set the focus
if (node
is IInputElement) Keyboard.Focus((IInputElement)node);
return false;
}
}
// If this dependency object is valid, check all child dependency objects
foreach (
object subnode
in LogicalTreeHelper.GetChildren(node))
{
if (subnode
is DependencyObject)
{
// If a child dependency object is invalid, return false immediately,
// otherwise keep checking
if (IsValid((DependencyObject)subnode) ==
false)
return false;
}
}
// All dependency objects are valid
return true;
}
在点击确定可使用该方法再次验证,在数据不合法的情况下,使用户无法提交
代码: 下载