Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
ObservableValidator je základní třída implementující rozhraní INotifyDataErrorInfo, která poskytuje podporu pro ověřování vlastností zpřístupněných ostatním modulům aplikace. Také dědí z ObservableObject, takže implementuje INotifyPropertyChanged a INotifyPropertyChanging také. Dá se použít jako výchozí bod pro všechny druhy objektů, které potřebují podporovat oznámení o změnách vlastností i ověřování vlastností.
Rozhraní API platformy:ObservableValidator, ObservableObject
Jak to funguje
ObservableValidator má následující hlavní funkce:
- Poskytuje základní implementaci pro
INotifyDataErrorInfoa zpřístupňuje událostErrorsChangeda ostatní nezbytná rozhraní API. - Poskytuje řadu dalších přetížení
SetProperty(kromě těch, která poskytuje základní třídaObservableObject), která umožňují automaticky ověřovat vlastnosti a před aktualizací jejich hodnot vyvolat potřebné události. - Poskytuje řadu přetížení
TrySetProperty, která jsou podobnáSetProperty, ale umožňují aktualizovat cílovou vlastnost pouze tehdy, pokud je validace úspěšná, a vrátit vygenerované chyby (pokud nějaké existují) pro další posouzení. - Zveřejňuje metodu
ValidateProperty, která může být užitečná k ruční aktivaci ověření konkrétní vlastnosti v případě, že jeho hodnota nebyla aktualizována, ale jeho ověření závisí na hodnotě jiné vlastnosti, která byla aktualizována. - Zpřístupňuje metodu
ValidateAllProperties, která automaticky spustí ověřování všech veřejných vlastností aktuální instance, pokud je na ně použit alespoň jeden atribut[ValidationAttribute]. - Zpřístupňuje metodu
ClearAllErrors, která může být užitečná při resetování modelu vázaného na nějaký formulář, který může uživatel chtít znovu vyplnit. - Nabízí řadu konstruktorů, které umožňují předání různých parametrů pro inicializaci
ValidationContextinstance, která se použije k ověření vlastností. To může být zvlášť užitečné při použití vlastních ověřovacích atributů, které můžou vyžadovat správné fungování dalších služeb nebo možností.
Jednoduchá vlastnost
Tady je příklad implementace vlastnosti, která podporuje oznámení o změnách i ověřování:
public class RegistrationForm : ObservableValidator
{
private string name;
[Required]
[MinLength(2)]
[MaxLength(100)]
public string Name
{
get => name;
set => SetProperty(ref name, value, true);
}
}
Zde voláme metodu SetProperty<T>(ref T, T, bool, string), kterou zpřístupňuje ObservableValidator, a dodatečný parametr bool nastavený na true znamená, že chceme vlastnost ověřit také při aktualizaci její hodnoty.
ObservableValidator automaticky spustí ověření pro každou novou hodnotu pomocí všech kontrol zadaných s atributy použitými u vlastnosti. Ostatní komponenty (například ovládací prvky uživatelského rozhraní) pak můžou pracovat s modelem viewmodel a upravit jejich stav tak, aby odrážely chyby, které jsou aktuálně přítomné v modelu viewmodel, tím, že se zaregistrují do ErrorsChanged a pomocí GetErrors(string) metody načtou seznam chyb pro každou upravenou vlastnost.
Vlastní metody ověřování
Ověření vlastnosti někdy vyžaduje, aby model zobrazení měl přístup k dalším službám, datům nebo jiným rozhraním API. Existují různé způsoby přidání vlastního ověření do vlastnosti v závislosti na scénáři a požadované úrovni flexibility. Tady je příklad, jak [CustomValidationAttribute] lze typ použít k označení, že je potřeba vyvolat konkrétní metodu, aby bylo možné provést dodatečné ověření vlastnosti:
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");
}
}
V tomto případě máme statickou ValidateName metodu, která provede ověření Name vlastnosti prostřednictvím služby vložené do našeho modelu viewmodel. Tato metoda přijímá hodnotu vlastnosti name a používanou instanci ValidationContext, která obsahuje například instanci modelu zobrazení, název ověřované vlastnosti a volitelně poskytovatele služeb a některé vlastní příznaky, které můžeme použít nebo nastavit. V tomto případě načítáme RegistrationForm instanci z kontextu ověření a tam používáme vloženou službu k ověření vlastnosti. Všimněte si, že toto ověření se provede vedle těch, které jsou uvedené v dalších atributech, takže můžeme kombinovat vlastní metody ověřování a existující ověřovací atributy, které se nám líbí.
Vlastní ověřovací atributy
Dalším způsobem, jak provádět vlastní ověřování, je implementovat vlastní [ValidationAttribute] a poté vložit logiku ověřování do přepsané metody IsValid. To umožňuje větší flexibilitu v porovnání s výše popsaným přístupem, protože je velmi snadné jednoduše znovu použít stejný atribut na více místech.
Předpokládejme, že jsme chtěli ověřit vlastnost na základě její relativní hodnoty s ohledem na jinou vlastnost ve stejném modelu viewmodel. Prvním krokem by bylo definovat vlastní [GreaterThanAttribute], takto:
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");
}
}
Dále můžeme tento atribut přidat do našeho ViewModelu:
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));
}
}
}
V tomto případě máme dvě číselné vlastnosti, které musí být v určitém rozsahu a s určitým vztahem mezi sebou (A musí být větší než B). Přidali jsme nový [GreaterThanAttribute] nad první vlastnost a také jsme do setteru vlastnosti B přidali volání ValidateProperty, aby se A znovu ověřil pokaždé, když se změní B (protože na něm závisí stav jeho ověření). Potřebujeme tyto dva řádky kódu v našem modelu viewmodel, abychom umožnili toto vlastní ověřování, a také získáme výhodu opětovného použití vlastního ověřovacího atributu, který by mohl být užitečný i v jiných modelech zobrazení v naší aplikaci. Tento přístup také pomáhá s modularizací kódu, protože logika ověřování je nyní zcela oddělená od samotné definice modelu viewmodel.
Příklady
- Podívejte se na ukázkovou aplikaci (pro více architektur uživatelského rozhraní) a podívejte se na sadu nástrojů MVVM v akci.
- Další příklady najdete také v jednotkových testech.