Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
ObservableValidator to klasa podstawowa implementująca interfejs INotifyDataErrorInfo, zapewniająca obsługę walidacji właściwości udostępnianych innym modułom aplikacji. Dziedziczy również po ObservableObject, więc implementuje także INotifyPropertyChanged i INotifyPropertyChanging. 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, udostępniając zdarzenieErrorsChangedoraz inne niezbędne interfejsy API. - Zapewnia szereg dodatkowych przeciążeń
SetProperty(oprócz tych udostępnianych przez klasę bazowąObservableObject), które umożliwiają automatyczne sprawdzanie poprawności właściwości i wywoływanie niezbędnych zdarzeń przed zaktualizowaniem ich wartości. - Udostępnia ona wiele przeciążeń
TrySetProperty, podobnych doSetProperty, ale umożliwiających aktualizację właściwości docelowej tylko wtedy, gdy walidacja zakończy się powodzeniem, oraz zwracających wygenerowane błędy (jeśli występują) do dalszej analizy. - 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. - Udostępnia metodę
ValidateAllProperties, która automatycznie wykonuje walidację wszystkich publicznych właściwości instancji w bieżącej instancji, o ile zastosowano do nich co najmniej jeden atrybut[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 szereg konstruktorów, które umożliwiają przekazanie różnych parametrów w celu zainicjowania wystąpienia
ValidationContext, które będzie używane do weryfikowania 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.
Prosta właściwość
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), udostępnianą przez ObservableValidator, a ten dodatkowy parametr bool ustawiony na true oznacza, że chcemy również weryfikować właściwość podczas aktualizacji jej wartości.
ObservableValidator automatycznie uruchomi walidację dla każdej nowej wartości, używając wszystkich sprawdzeń określonych przez atrybuty zastosowane 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 przyjmuje wartość właściwości name oraz używaną instancję ValidationContext, która zawiera takie elementy jak instancja modelu widoku, nazwa sprawdzanej właściwości, a opcjonalnie także dostawca usług i pewne flagi niestandardowe, których możemy użyć lub które możemy ustawić. W tym przypadku pobieramy instancję RegistrationForm z kontekstu walidacji, a następnie używamy wstrzykniętej usługi do 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 byłoby zdefiniowanie niestandardowego elementu [GreaterThanAttribute], na przykład tak:
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 naszego modelu widoku:
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 nowe [GreaterThanAttribute] nad pierwszą właściwością, a także wywołanie ValidateProperty w setterze dla B, aby A było ponownie sprawdzane za każdym razem, gdy B się zmienia (ponieważ stan jego walidacji od niej zależy). 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.