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 ObservableObject
elementu , 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
INotifyDataErrorInfo
programu , uwidaczniającErrorsChanged
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 doSetProperty
, 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 ObservableValidator
parametr , 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 B
elementu , 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.