BusinessLayerValidation,即业务层验证,是指在软件应用程序的业务逻辑层(Business Layer)中执行的验证过程。业务逻辑层是应用程序架构中的一个关键部分,负责处理与业务规则和逻辑相关的操作。业务层验证的主要目的是确保数据在业务规则和逻辑上的有效性,从而维护数据的完整性和一致性。
在WPF Samples中有一个Demo提到了BusinessLayerValidation。
该Demo结构如下所示:
实现的效果如下所示:
当输入值是字符时会提示不是正确的形式,当输入小于0或大于150的数时会有一个自定义的提示。
IDataErrorInfo接口
在WPF中实现业务逻辑层的验证可以使用IDataErrorInfo接口与INotifyDataErrorInfo 接口。这个Demo使用的是IDataErrorInfo接口。IDataErrorInfo接口主要用于在数据绑定场景中提供自定义的验证错误信息。IDataErrorInfo接口包含两个成员:
string IDataErrorInfo.Error { get; }
这个属性返回一个字符串,表示整个对象的错误信息。如果对象没有错误,应该返回一个空字符串或null。
string IDataErrorInfo.this[string columnName] { get; }
这个索引器用于返回指定属性的错误信息。columnName参数表示属性的名称,索引器应该返回该属性的错误信息。如果属性没有错误,应该返回一个空字符串或null。
通过实现IDataErrorInfo接口,可以为数据对象提供详细的验证错误信息,这些信息可以在用户界面中显示,帮助用户理解和纠正输入错误。
定义一个实现该接口的Person类:
public class Person : IDataErrorInfo
{
public int Age { get; set; }
public string Error => null;
public string this[string name]
{
get
{
string result = null;
if (name == "Age")
{
if (Age < 0 || Age > 150)
{
result = "Age must not be less than 0 or greater than 150.";
}
}
return result;
}
}
}
定义资源
<local:Person x:Key="Data"/>
现在xaml中定义了一个Person对象为资源,键名为Data。
<!--The tool tip for the TextBox to display the validation error message.-->
<Style x:Key="TextBoxInError" TargetType="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>
为TextBox控件定义了一个键名为TextBoxInError的样式(Style)。
触发器(Trigger)
在WPF中,触发器(Trigger)是一种用于在特定条件满足时改变控件外观或行为的机制。Trigger通常用于Style
或ControlTemplate中,以便在属性值变化或事件发生时自动应用视觉效果或行为。
WPF 中的Trigger可以分为以下几类:
Property Trigger
是最常用的触发器类型。它根据依赖属性的值来应用视觉效果或行为。
示例:
<Style TargetType="Button">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Yellow"/>
</Trigger>
</Style.Triggers>
</Style>
在这个例子中,当鼠标悬停在按钮上时,按钮的背景色会变为黄色。
Data Trigger
类似于Property Trigger,但它用于绑定数据上下文中的属性,而不是控件本身的依赖属性。
示例:
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsEnabled}" Value="False">
<Setter Property="Foreground" Value="Gray"/>
</DataTrigger>
</Style.Triggers>
</Style>
在这个例子中,当数据上下文中的IsEnabled属性为False时,文本块的前景色会变为灰色。
Event Trigger
用于在特定事件发生时执行动画或命令。
示例:
<Button Content="Click Me">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:1"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
在这个例子中,当按钮被点击时,按钮的透明度会从 1 变为 0,持续 1 秒钟。
MultiTrigger
和MultiDataTrigger
允许你指定多个条件,只有当所有条件都满足时,才会应用视觉效果或行为。
示例:
<Style TargetType="TextBox">
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsFocused" Value="True"/>
<Condition Property="Text" Value=""/>
</MultiTrigger.Conditions>
<Setter Property="BorderBrush" Value="Red"/>
</MultiTrigger>
</Style.Triggers>
</Style>
在这个例子中,当文本框获得焦点且文本为空时,文本框的边框颜色会变为红色。
通过使用这些触发器,可以创建动态和响应式的用户界面,根据不同的条件自动调整控件的外观和行为。
通过回顾WPF中的这些触发器,再来看看现在遇到的触发器:
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
这是属性触发器,当Validation.HasError属性的值为true时,会将ToolTip的值设置为(Validation.Errors)[0].ErrorContent的值。
之前我们已经接触过StaticSource这表示是静态资源,现在这里是RelativeSource,让我们来了解一下它吧。
RelativeSource是WPF中的一个绑定标记扩展,用于指定数据绑定的源相对于绑定目标的位置。它允许你在绑定表达式中引用相对于当前控件或数据上下文的另一个对象,而不是直接指定一个固定的源对象。
RelativeSource可以用于以下几种模式:
可以创建更灵活和动态的数据绑定,特别是在处理复杂的用户界面和控件模板时。
再来看文本框部分:
<StackPanel Margin="20">
<TextBlock>Enter your age:</TextBlock>
<TextBox Style="{StaticResource TextBoxInError}">
<TextBox.Text>
<!--By setting ValidatesOnExceptions to True, it checks for exceptions
that are thrown during the update of the source property.
An alternative syntax is to add <ExceptionValidationRule/> within
the <Binding.ValidationRules> section.-->
<Binding Path="Age" Source="{StaticResource Data}"
ValidatesOnExceptions="True"
UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<!--DataErrorValidationRule checks for validation
errors raised by the IDataErrorInfo object.-->
<!--Alternatively, you can set ValidationOnDataErrors="True" on the Binding.-->
<DataErrorValidationRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<TextBlock>Mouse-over to see the validation error message.</TextBlock>
</StackPanel>
首先为文本框设置了键名为TextBoxInError的样式。
<TextBox.Text>
<Binding Path="Age" Source="{StaticResource Data}"
ValidatesOnExceptions="True"
UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<DataErrorValidationRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
ValidatesOnExceptions属性指定了是否在数据绑定过程中捕获并处理异常。ValidatesOnExceptions="True"
表示如果在数据绑定过程中发生了异常(例如,数据源的Age属性在设置值时抛出了异常),这个异常将会被捕获并用于验证目的,通常用于显示错误信息或阻止无效数据的输入。
<Binding.ValidationRules>
<DataErrorValidationRule/>
</Binding.ValidationRules>
Binding.ValidationRules是一个集合属性,用于存储数据绑定的验证规则。这些验证规则用于在数据绑定过程中检查数据的合法性。DataErrorValidationRule是WPF中预定义的一种验证规则。它用于检查数据对象是否实现了
IDataErrorInfo接口,并根据该接口提供的信息进行验证。当数据对象实现了IDataErrorInfo接口时,DataErrorValidationRule会调用接口中的方法来获取错误信息,并在数据绑定过程中应用这些错误信息。
验证类型
默认验证:当你输入 "a" 时,WPF尝试将 "a" 转换为整数,但由于 "a" 不是有效的整数,默认验证机制会生成一个错误,提示 "不是正确的格式"。
自定义验证:在你输入一个有效的整数后,WPF会继续检查这个值是否符合你的自定义验证规则(例如,年龄必须在0到150之间)。如果值不符合规则,你会看到 "Age must not be less than 0 or greater than 150" 的提示。
在WPF中,数据绑定的验证过程通常遵循以下顺序:
数据转换(Data Conversion):
如果绑定的数据需要从一种类型转换为另一种类型(例如,从字符串转换为整数),WPF会首先尝试进行类型转换。如果转换失败,会抛出一个异常,这个异常可以被捕获并用于验证目的。
验证规则(Validation Rules):
如果绑定的ValidationRules集合中定义了任何自定义的验证规则,WPF会按照这些规则的顺序依次执行它们。每个验证规则可以返回一个ValidationResult对象,指示数据是否有效以及相关的错误信息。
异常验证(Exception Validation):
如果绑定的ValidatesOnExceptions属性设置为True,WPF会在数据绑定的过程中捕获任何抛出的异常,并将这些异常转换为验证错误。这通常用于捕获数据转换或数据设置过程中的异常。
IDataErrorInfo 验证:
如果数据对象实现了IDataErrorInfo接口,WPF会调用该接口的方法来获取错误信息。DataErrorValidationRule
可以用于在数据绑定过程中应用这些错误信息。
INotifyDataErrorInfo 验证:
如果数据对象实现了INotifyDataErrorInfo接口,WPF会监听该接口的事件,并在数据发生错误时获取错误信息。这种验证方式提供了更灵活和异步的验证机制。
这些验证步骤并不是严格按顺序执行的,而是根据绑定的配置和数据对象的实现情况来决定。例如,如果绑定的
ValidationRules集合中包含了DataErrorValidationRule,那么IDataErrorInfo验证会在验证规则执行的过程中被触发。
WPF中的验证顺序是灵活的,并且可以根据具体的绑定配置和数据对象的实现情况来调整。通常情况下,数据转换和自定义验证规则会在异常验证和IDataErrorInfo验证之前执行。
[WPF-Samples/Data Binding/BusinessLayerValidation at main · microsoft/WPF-Samples (github.com)](https://github.com/microsoft/WPF-Samples/tree/main/Data Binding/BusinessLayerValidation)