CommunityToolkit.Mvvm笔记---ObservableValidator

发布于:2024-04-18 ⋅ 阅读:(23) ⋅ 点赞:(0)

ObservableValidator 是实现 INotifyDataErrorInfo 接口的基类,它支持验证向其他应用程序模块公开的属性。 它也继承自 ObservableObject,因此它还可实现 INotifyPropertyChanged 和 INotifyPropertyChanging。 它可用作需要支持属性更改通知和属性验证的各种对象的起点。

平台 API:ObservableValidatorObservableObject

工作原理(摘抄自官网)

ObservableValidator 包含以下主要功能:

  • 它提供对 INotifyDataErrorInfo 的基本实现,从而公开 ErrorsChanged 事件和其他必要的 API。
  • 它提供一系列额外的 SetProperty 重载(ObservableObject 基类提供的重载除外),这些重载提供在更新属性值之前自动验证属性和引发必要事件的功能。
  • 它公开了许多 TrySetProperty 重载,这些重载类似于 SetProperty 但仅在验证成功时更新目标属性,并在出错时返回生成的错误以供进一步检查。
  • 它公开了 ValidateProperty 方法,这对于手动触发对特定属性的验证非常有用,以防其值尚未更新,但其验证依赖于已更新的另一个属性的值。
  • 它公开了 ValidateAllProperties 方法,这会自动执行对当前实例中所有公共实例属性的验证,前提是它们至少应用了一个 [ValidationAttribute]
  • 它公开了 ClearAllErrors 方法,该方法在重置绑定到用户可能需要再次填充的某个表单的模型时非常有用。
  • 它提供许多构造函数,这些函数允许传递不同的参数来初始化将用于验证属性的 ValidationContext 实例。 使用可能需要其他服务或选项才能正常工作的自定义验证特性时,这尤其有用。
具体实例

xaml试图

<Page x:Class="Event.Views.Pages.RegistrationForm"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:local="clr-namespace:Event.Views.Pages"
      mc:Ignorable="d" 
      d:DesignHeight="450" d:DesignWidth="800"
      Title="RegistrationForm">
    <Page.Resources>
        <Style TargetType="TextBox">
            <Setter Property="Validation.ErrorTemplate">
                <Setter.Value>
                    <ControlTemplate>
                        <StackPanel>
                            <AdornedElementPlaceholder />
                            <ItemsControl ItemsSource="{Binding}">
                                <ItemsControl.ItemTemplate>
                                    <DataTemplate>
                                        <TextBlock
                                           Foreground="Red"
                                           Text="{Binding ErrorContent}" />
                                    </DataTemplate>
                                </ItemsControl.ItemTemplate>
                            </ItemsControl>
                        </StackPanel>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Page.Resources>
    <Grid>
        <StackPanel>
            <TextBox Width="150" Height="30" VerticalContentAlignment="Center" Margin="0 10 0 0 "  Text="{Binding Email,UpdateSourceTrigger=PropertyChanged, NotifyOnValidationError=true, ValidatesOnDataErrors=true}" 
                    ></TextBox>
            
            <!--<Label Content="{Binding Path=(Validation.Errors)[0].ErrorContent, RelativeSource={RelativeSource Self}}"></Label>-->
            <TextBox Width="150" Height="30" VerticalContentAlignment="Center" Margin="0 20 0 0 " Text="{Binding Name,UpdateSourceTrigger=PropertyChanged, NotifyOnValidationError=true, ValidatesOnDataErrors=true}" ></TextBox>
            <TextBox Width="150" Height="30" VerticalContentAlignment="Center" Margin="0 20 0 0"
                     Text="{Binding Age,UpdateSourceTrigger=PropertyChanged, NotifyOnValidationError=true, ValidatesOnDataErrors=true}"></TextBox>
            <Button Width="150" Height="30" Margin="0 20 0 0" Command="{Binding SubmitCommand}">Submit</Button>
        </StackPanel>
        
    </Grid>
</Page>

创建viewModel:

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Event.Views.Pages;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace Event.ViewModels.Pages
{
    public partial  class RegistrationFormViewModel : ObservableValidator
    {
        private string _email;

        //[ObservableProperty]
        [Required(ErrorMessage = "Email is required")]
        [EmailAddress(ErrorMessage = "Invaid email address")]
        public string Email
        {
            get => _email;
            set => SetProperty(ref _email, value, true);
        }

        private string _name;
        [Required(ErrorMessage ="name不可为空")]
        [MinLength(2,ErrorMessage ="name长度不小于2")]
        [MaxLength(30,ErrorMessage ="name长度不大于30")]
        //
        public string Name
        {
            get => _name;
            set => SetProperty(ref _name, value, true);

        }
        private int _age;
        [CustomValidation(typeof(RegistrationFormViewModel), nameof(ValidateAge1))]
        public int Age
        {
            get => (int)_age;
            set => SetProperty(ref _age, value, true);
        }

        public static ValidationResult ValidateAge1(int age, ValidationContext context)
        {
            if (age >= 18 && age <= 100)
            {
                return ValidationResult.Success;
            }
            return new("年龄最小18岁最大100岁");

        }
        [RelayCommand]
        public void Submit()
        {
            ValidateAllProperties(); // Validates all properties with validation attributes

            if (HasErrors)
            {
                // Handle validation errors
                // For example, inform the user to correct the errors
                MessageBox.Show("error");
            }
            else
            {
                // Process the data as there are no validation errors
                MessageBox.Show("right");
            }
        }
        public RegistrationFormViewModel() {

        }
       
    }
}

 结果如下:

 可实时校验。

上述例子中有内置验证,也有自定义验证,也可参考官网。