背景
在开发过程中验证数据是否符合要求是经常遇到的,如IP的验证、邮箱的验证、电话号码的验证等等。C#中System.ComponentModel.DataAnnotations 命名空间下提供了一些常用特性用于数据的验证,常用的如Required、MaxLength、MinLength、Key、NotMapped等等,满足了多数时候的使用需求,但对于一些场景,还不能满足项目需要的。这时就需要自定义相应的验证特性,以满足工程需要。
开发环境
WIN11
VS2022
MVVM Toolkit7.1.2
.net core6
自定义验证特性
自定义方法如下
- 添加AttributeUsage特性。
- 继承于ValidationAttribute,重写IsValid方法。
以自定义端口验证特性进行详细的说明:
cs
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class PortNumberAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (value == null)
{
return new ValidationResult("端口号不能为空");
}
var portString = value.ToString();
if (!int.TryParse(portString, out int port))
{
return new ValidationResult("请输入有效的端口号");
}
if (port < 0 || port > 65535)
{
return new ValidationResult("端口号必须在0到65535之间");
}
// 可以在这里检查端口是否已被使用等
return ValidationResult.Success;
}
}
注意:
AttributeUsage中添加了AttributeTargets.Property,它指此验证特性可用于Property(属性)上;
AllowMultiple = false 表示在同一属性上不可多次使用此自定义验证特性;
Inherited = true 表示这个验证特性是可以继承的。
VM使用如下
使用方法如下(以下代码使用了MVVM Toolkit,整个VM继承于它的ObservableValidator以进行数据验证,因此SetProperty与GetErrors可直接使用):
cs
[ObservableProperty]
private string localPortErrorMessage;
[PortNumber(ErrorMessage = "请输入有效的端口号")]
public string LocalTerminalPort
{
get => localTerminalPort;
set
{
SetProperty(ref localTerminalPort, value, true);
LocalPortErrorMessage = GetErrors(nameof(LocalTerminalPort)).Cast<ValidationResult>().FirstOrDefault()?.ErrorMessage ?? string.Empty;
}
}
上述代码中的LocalPortErrorMessage即是出错的报错信息,绑定此信息到xaml上,填写出错时即可及时看到出错信息。
在VM中若有多个验证的情况下,一个不满足时就不请允许进行后续操作,这时可利用ObservableValidator 提供的**HasErrors**进行相应判断。
x:Bind属性注意事项
xaml中绑定时需要注意,由于验证特性是在set时进行验证,然后设置相应的错误信息,也就是说需要验证的属性变化时就要立马验证,如果使用x:Bind进行验证时,则需要设置Mode=TwoWay且UpdateSourceTrigger=PropertyChanged,即如下所示:
XML
<TextBox
Name="password"
Width="500"
Height="66"
MaxLength="10"
Text="{x:Bind VM.Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
若使用x:Bind不设置Mode=TwoWay,则会报下述错误:
Invalid binding assignment : 'UpdateSourceTrigger' may only be used with binding 'Mode=TwoWay'
若使用x:Bind不设置UpdateSourceTrigger=PropertyChanged,则会导致属性更新时不会及时通知VM,也就不会马上进行数据验证。
使用Bing暂未发现上述问题。
参考连接
https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.inotifydataerrorinfo?view=net-8.0
ObservableValidator Class (CommunityToolkit.Mvvm.ComponentModel) | Microsoft Learn
System.ComponentModel.DataAnnotations 命名空间 | Microsoft Learn