Avalonia低入侵数据验证实现

1.概要

目前在.NET8 Avalonia 11.0.10版本中有三种常见的数据验证方式:

  1. IDataErrorInfo:这是一种较旧的数据验证方式,主要用于WPF和WinForms。在这种方法中,模型需要实现IDataErrorInfo接口,该接口包含一个索引器和一个Error属性。索引器用于获取特定属性的错误消息,Error属性用于获取对象级别的错误消息。

  2. INotifyDataErrorInfo:这是一种更现代的数据验证方式,它允许异步验证并能提供多个错误消息。在这种方法中,模型需要实现INotifyDataErrorInfo接口,该接口包含一个ErrorsChanged事件和两个方法:GetErrors和HasErrors。GetErrors方法用于获取特定属性的错误消息,HasErrors属性用于确定对象是否有任何错误。

  3. 还有一种通过FluentValidation库进行数据验证的方式。

    FluentValidation是一个流行的.NET库,用于构建强大、可维护的验证规则。它使用流畅的API创建验证规则,支持复杂的验证场景,并可以很好地与Avalonia一起工作。

    使用FluentValidation,您可以在单独的验证类中定义规则,这样可以使模型类保持简洁。

在Avalonia中,最佳实践是使用INotifyDataErrorInfo接口进行数据验证。

2.详细内容

在以上的三种验证中我选择的是INotifyDataErrorInfo来实现,看到的一些示例实现的比较麻烦或者不够简洁我做了一些改进。

ValidateBindbleBase

因为INotifyDataErrorInfo需要在每个ViewModel或Model中进行数据验证,所以我将BindableBase和INotifyDataErrorInfo进行封装。这样继承了之后就不需要每次都编写相同的逻辑。

public class ValidateBindbleBase : BindableBase, INotifyDataErrorInfo
{
    private readonly Dictionary<string, ICollection<string>> _validationErrors = new Dictionary<string, ICollection<string>>();

    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

    public bool HasErrors => _validationErrors.Count > 0;

    public IEnumerable GetErrors(string propertyName)
    {
        //If null is not returned, there will be two identical exception prompts on the view
        return null;
    }

    protected void ValidateProperty<T>(string propertyName, T value)
    {
        if (value == null) return;

        var context = new ValidationContext(this) { MemberName = propertyName };
        var validationResults = new List<ValidationResult>();

        Validator.TryValidateProperty(value, context, validationResults);

        if (_validationErrors.ContainsKey(propertyName))
        {
            _validationErrors.Remove(propertyName);
        }

        HandleValidationResults(propertyName, validationResults);
    }

    private void HandleValidationResults(string propertyName, ICollection<ValidationResult> validationResults)
    {
        if (validationResults.Any())
        {
            _validationErrors.Add(propertyName, new List<string>());
            foreach (var validationResult in validationResults)
            {
                _validationErrors[propertyName].Add(validationResult?.ErrorMessage);
            }

            ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
        }
    }
}

ViewModel

这里在ViewModel层做了一个简单的示例,ViewModel继承ValidateBindbleBase之后即获得了数据验证和数据通知的能力。再通过系统或自定义的验证特性进行附加,这样就可以复用验证规则避免出现大量的if else。

public class ViewModel : ValidateBindbleBase
{
    private string _packetName;

    [MinLength(2)]
    [StringValidator]
    public string PacketName 
    { 
        get => _packetName;
        set 
        {
            if (SetProperty(ref _packetName, value))
                ValidateProperty(nameof(PacketName), value);
        }
    }
}

Validation

如果系统的验证特性不能满足需要,那么我们可以通过自定义特性继承ValidationAttribute,通过重写IsValid、FormatErrorMessage来实现自定义验证规则和验证错误提示。

public partial class StringValidator : ValidationAttribute
{
    public override string FormatErrorMessage(string name)
    {
        return "The field is invaild!";
    }

    public override bool IsValid(object? value) 
    {
        try
        {
           return  StringRegex().IsMatch(value?.ToString());
        }
        catch
        {
            return false;
        }
    }

    [GeneratedRegex(@"^[a-zA-Z0-9_\-\.\u4e00-\u9fa5]+$")]
    private static partial Regex StringRegex();
}

View

在view层正常绑定即可。

<TextBox
    Grid.Row="2"
    Grid.Column="1"
    Margin="5"
    Text="{Binding CurrnetConfig.PacketName}" />

481cc4ff1d9d045574de07daef58a82c.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果您想在Avalonia应用程序中导入数据,可以按照以下步骤进行操作: 1. 确定您要导入的数据类型和格式。 2. 创建一个类来表示您的数据对象,并定义其属性。 3. 创建一个数据访问层来获取数据。您可以使用 ADO.NET 或 Entity Framework 等框架来访问数据库,或使用 Web API 来访问 Web 服务。 4. 在您的视图模型中创建一个集合属性来保存您的数据对象。 5. 在视图中使用绑定来显示您的数据。 以下是一个简单的示例,演示如何在Avalonia应用程序中导入数据: ```csharp //定义数据对象 public class Customer { public int Id { get; set; } public string Name { get; set; } public string Address { get; set; } } //创建数据访问层 public class CustomerRepository { public List<Customer> GetCustomers() { //使用 Entity Framework 或 ADO.NET 获取数据 //返回一个包含 Customer 对象的 List } } //在视图模型中创建一个集合属性 public class MainViewModel : ViewModelBase { private CustomerRepository _repository; public MainViewModel() { _repository = new CustomerRepository(); Customers = new ObservableCollection<Customer>(_repository.GetCustomers()); } public ObservableCollection<Customer> Customers { get; set; } } //在视图中使用绑定来显示数据 <ListBox Items="{Binding Customers}"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel> <TextBlock Text="{Binding Name}"/> <TextBlock Text="{Binding Address}"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox> ``` 这只是一个简单的示例,您可以根据您的具体需求进行更改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值