Udostępnij za pośrednictwem


Obserwowalnyvalidator

Jest ObservableValidator to klasa podstawowa implementując INotifyDataErrorInfo interfejs, zapewniając obsługę walidacji właściwości uwidocznionych w innych modułach aplikacji. Dziedziczy on również z ObservableObjectelementu , więc implementuje INotifyPropertyChanged i INotifyPropertyChanging , jak również. Może służyć jako punkt wyjścia dla wszystkich rodzajów obiektów, które muszą obsługiwać zarówno powiadomienia o zmianie właściwości, jak i walidację właściwości.

Interfejsy API platformy: ObservableValidator, ObservableObject

Jak to działa

ObservableValidator ma następujące główne funkcje:

  • Zapewnia podstawową implementację dla INotifyDataErrorInfoprogramu , uwidaczniając ErrorsChanged zdarzenie i inne niezbędne interfejsy API.
  • Zapewnia szereg dodatkowych SetProperty przeciążeń (na podstawie tych dostarczonych przez klasę bazową ObservableObject ), które oferują możliwość automatycznego weryfikowania właściwości i podnoszenia niezbędnych zdarzeń przed zaktualizowaniem ich wartości.
  • Uwidacznia ona wiele TrySetProperty przeciążeń, które są podobne do SetProperty , ale z możliwością aktualizowania właściwości docelowej tylko wtedy, gdy walidacja zakończy się pomyślnie, i zwrócić wygenerowane błędy (jeśli istnieją) do dalszej inspekcji.
  • Uwidacznia metodę ValidateProperty , która może być przydatna do ręcznego wyzwalania walidacji określonej właściwości w przypadku, gdy jej wartość nie została zaktualizowana, ale jej walidacja zależy od wartości innej właściwości, która zamiast tego została zaktualizowana.
  • Uwidacznia metodę ValidateAllProperties , która automatycznie wykonuje walidację wszystkich właściwości wystąpienia publicznego w bieżącym wystąpieniu, pod warunkiem, że zastosowano do nich co najmniej jedną [ValidationAttribute] .
  • Uwidacznia metodę ClearAllErrors , która może być przydatna podczas resetowania modelu powiązanego z formularzem, który użytkownik może chcieć wypełnić ponownie.
  • Oferuje on szereg konstruktorów, które umożliwiają przekazywanie różnych parametrów w celu zainicjowania ValidationContext wystąpienia, które będzie używane do sprawdzania poprawności właściwości. Może to być szczególnie przydatne w przypadku używania niestandardowych atrybutów weryfikacji, które mogą wymagać poprawnego działania dodatkowych usług lub opcji.

Właściwość Simple

Oto przykład implementacji właściwości obsługującej zarówno powiadomienia o zmianie, jak i weryfikację:

public class RegistrationForm : ObservableValidator
{
    private string name;

    [Required]
    [MinLength(2)]
    [MaxLength(100)]
    public string Name
    {
        get => name;
        set => SetProperty(ref name, value, true);
    }
}

W tym miejscu wywołujemy metodę SetProperty<T>(ref T, T, bool, string) uwidacznianą przez ObservableValidatorparametr , a ten dodatkowy bool parametr wskazuje true , że chcemy również zweryfikować właściwość po zaktualizowaniu jej wartości. ObservableValidator spowoduje automatyczne uruchomienie walidacji dla każdej nowej wartości przy użyciu wszystkich testów określonych z atrybutami zastosowanymi do właściwości. Inne składniki (takie jak kontrolki interfejsu użytkownika) mogą następnie wchodzić w interakcje z modelem widoku i modyfikować ich stan, aby odzwierciedlać błędy obecne w modelu widoków, rejestrując się ErrorsChanged i używając GetErrors(string) metody w celu pobrania listy błędów dla każdej zmodyfikowanej właściwości.

Niestandardowe metody walidacji

Czasami walidacja właściwości wymaga, aby model widoku miał dostęp do dodatkowych usług, danych lub innych interfejsów API. Istnieją różne sposoby dodawania weryfikacji niestandardowej do właściwości w zależności od scenariusza i wymaganego poziomu elastyczności. Oto przykład użycia [CustomValidationAttribute] typu w celu wskazania, że należy wywołać określoną metodę w celu przeprowadzenia dodatkowej weryfikacji właściwości:

public class RegistrationForm : ObservableValidator
{
    private readonly IFancyService service;

    public RegistrationForm(IFancyService service)
    {
        this.service = service;
    }

    private string name;

    [Required]
    [MinLength(2)]
    [MaxLength(100)]
    [CustomValidation(typeof(RegistrationForm), nameof(ValidateName))]
    public string Name
    {
        get => this.name;
        set => SetProperty(ref this.name, value, true);
    }

    public static ValidationResult ValidateName(string name, ValidationContext context)
    {
        RegistrationForm instance = (RegistrationForm)context.ObjectInstance;
        bool isValid = instance.service.Validate(name);

        if (isValid)
        {
            return ValidationResult.Success;
        }

        return new("The name was not validated by the fancy service");
    }
}

W tym przypadku mamy metodę statyczną ValidateName , która przeprowadzi walidację właściwości Name za pośrednictwem usługi wprowadzonej do modelu widoków. Ta metoda odbiera name wartość właściwości i ValidationContext używane wystąpienie, które zawiera takie elementy jak wystąpienie modelu viewmodel, nazwa weryfikowanej właściwości oraz opcjonalnie dostawca usług i niektóre flagi niestandardowe, których możemy użyć lub ustawić. W tym przypadku pobieramy RegistrationForm wystąpienie z kontekstu weryfikacji, a następnie używamy wprowadzonej usługi w celu zweryfikowania właściwości. Należy pamiętać, że ta walidacja zostanie wykonana obok tych określonych w innych atrybutach, dlatego możemy połączyć niestandardowe metody walidacji i istniejące atrybuty weryfikacji, jednak nam się podoba.

Niestandardowe atrybuty walidacji

Innym sposobem wykonania walidacji niestandardowej jest zaimplementowanie niestandardowej [ValidationAttribute] , a następnie wstawienie logiki walidacji do metody zastąpionej IsValid . Zapewnia to dodatkową elastyczność w porównaniu z opisanym powyżej podejściem, ponieważ bardzo łatwo jest po prostu ponownie użyć tego samego atrybutu w wielu miejscach.

Załóżmy, że chcemy zweryfikować właściwość na podstawie jej względnej wartości względem innej właściwości w tym samym modelu widoków. Pierwszym krokiem jest zdefiniowanie niestandardowego [GreaterThanAttribute]elementu w następujący sposób:

public sealed class GreaterThanAttribute : ValidationAttribute
{
    public GreaterThanAttribute(string propertyName)
    {
        PropertyName = propertyName;
    }

    public string PropertyName { get; }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        object
            instance = validationContext.ObjectInstance,
            otherValue = instance.GetType().GetProperty(PropertyName).GetValue(instance);

        if (((IComparable)value).CompareTo(otherValue) > 0)
        {
            return ValidationResult.Success;
        }

        return new("The current value is smaller than the other one");
    }
}

Następnie możemy dodać ten atrybut do modelu viewmodel:

public class ComparableModel : ObservableValidator
{
    private int a;

    [Range(10, 100)]
    [GreaterThan(nameof(B))]
    public int A
    {
        get => this.a;
        set => SetProperty(ref this.a, value, true);
    }

    private int b;

    [Range(20, 80)]
    public int B
    {
        get => this.b;
        set
        {
            SetProperty(ref this.b, value, true);
            ValidateProperty(A, nameof(A));
        }
    }
}

W tym przypadku mamy dwie właściwości liczbowe, które muszą znajdować się w określonym zakresie i z określoną relacją między sobą (A muszą być większe niż B). Dodaliśmy nową [GreaterThanAttribute] właściwość w pierwszej właściwości, a także dodaliśmy wywołanie metody ValidateProperty w metodzie setter dla Belementu , aby A było ponownie weryfikowane za każdym razem, gdy B zmienia się (ponieważ jego stan weryfikacji zależy od niego). Potrzebujemy tylko tych dwóch wierszy kodu w modelu viewmodel, aby włączyć tę niestandardową walidację, a także uzyskamy korzyści z posiadania niestandardowego atrybutu weryfikacji wielokrotnego użytku, który może być przydatny w innych modelach widoków w naszej aplikacji. Takie podejście pomaga również w modułyzacji kodu, ponieważ logika walidacji jest teraz całkowicie oddzielona od samej definicji modelu widoku.

Przykłady

  • Zapoznaj się z przykładową aplikacją (dla wielu struktur interfejsu użytkownika), aby zobaczyć, jak działa zestaw narzędzi MVVM Toolkit.
  • Więcej przykładów można również znaleźć w testach jednostkowych.