ObservableValidator

ObservableValidator, INotifyDataErrorInfo arabirimini uygulayan ve diğer uygulama modüllerine sunulan özelliklerin doğrulanmasını destekleyen bir temel sınıftır. Ayrıca ObservableObject öğesinden devralır, bu nedenle INotifyPropertyChanged ve INotifyPropertyChanging öğelerini de uygular. Hem özellik değişikliği bildirimlerini hem de özellik doğrulamasını desteklemesi gereken her tür nesne için başlangıç noktası olarak kullanılabilir.

Platform API'leri:ObservableValidator, ObservableObject

Nasıl çalışır?

ObservableValidator aşağıdaki ana özelliklere sahiptir:

  • ErrorsChanged olayını ve gerekli diğer API'leri kullanıma sunan INotifyDataErrorInfo için temel bir uygulama sunar.
  • Temel ObservableObject sınıfı tarafından sağlananlara ek olarak, özellikleri otomatik olarak doğrulama ve değerlerini güncellemeden önce gerekli olayları tetikleme olanağı sunan bir dizi ek SetProperty aşırı yüklemesi sağlar.
  • SetProperty'e benzer, ancak yalnızca doğrulama başarılı olursa hedef özelliği güncelleyebilen ve daha sonra incelenmek üzere oluşturulan hataları (varsa) döndürebilen bir dizi TrySetProperty aşırı yüklemesi sunar.
  • ValidateProperty yöntemini kullanıma sunar; bu yöntem, değeri güncellenmemiş ancak doğrulaması bunun yerine güncellenmiş başka bir özelliğin değerine bağlı olan belirli bir özelliğin doğrulamasını el ile tetiklemek için yararlı olabilir.
  • En az bir [ValidationAttribute] uygulanmışsa, geçerli örnekteki tüm ortak örnek özelliklerinin doğrulamasını otomatik olarak gerçekleştiren ValidateAllProperties yöntemini kullanıma sunar.
  • Kullanıcının yeniden doldurmak isteyebileceği bir forma bağlı modeli sıfırlarken yararlı olabilecek bir ClearAllErrors yöntemi kullanıma sunar.
  • Özellikleri doğrulamak için kullanılacak ValidationContext örneğini başlatmak üzere farklı parametrelerin geçirilmesine olanak tanıyan çeşitli yapıcılar sunar. Bu, özellikle ek hizmetlerin veya seçeneklerin düzgün çalışmasını gerektirebilecek özel doğrulama özniteliklerini kullanırken yararlı olabilir.

Basit özellik

Hem değişiklik bildirimlerini hem de doğrulamayı destekleyen bir özelliğin nasıl uygulandığını gösteren bir örnek aşağıda verilmiştir:

public class RegistrationForm : ObservableValidator
{
    private string name;

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

Burada, ObservableValidator tarafından kullanıma sunulan SetProperty<T>(ref T, T, bool, string) yöntemini çağırıyoruz ve true olarak ayarlanmış bu ek bool parametresi, değeri güncellendiğinde özelliği de doğrulamak istediğimizi gösteriyor. ObservableValidator özelliğine uygulanan özniteliklerle belirtilen tüm denetimleri kullanarak her yeni değerde doğrulamayı otomatik olarak çalıştırır. Daha sonra diğer bileşenler (UI denetimleri gibi), görünüm modeliyle etkileşime girebilir ve ErrorsChanged öğesine kaydolup, değiştirilmiş her özellik için hata listesini almak üzere GetErrors(string) yöntemini kullanarak durumlarını o anda görünüm modelinde bulunan hataları yansıtacak şekilde değiştirebilir.

Özel doğrulama yöntemleri

Bazen bir özelliğin doğrulanıyor olması için görünüm modelinin ek hizmetlere, verilere veya diğer API'lere erişimi olması gerekir. Senaryoya ve gerekli esneklik düzeyine bağlı olarak bir özelliğe özel doğrulama eklemenin farklı yolları vardır. Aşağıda, bir özelliğin ek doğrulamasını [CustomValidationAttribute] gerçekleştirmek için belirli bir yöntemin çağrılması gerektiğini belirtmek için türün nasıl kullanılabileceğini gösteren bir örnek verilmiştir:

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");
    }
}

Bu durumda, görünüm modelimize enjekte edilen bir hizmet aracılığıyla Name özelliği üzerinde doğrulama gerçekleştirecek statik bir ValidateName yöntemimiz var. Bu yöntem, name özellik değerini ve kullanımda olan ValidationContext örneğini alır; bu örnek, viewmodel örneği, doğrulanan özelliğin adı ve isteğe bağlı olarak kullanabileceğimiz veya ayarlayabileceğimiz bazı özel bayrakların yanı sıra bir hizmet sağlayıcı gibi öğeleri içerir. Bu durumda, doğrulama bağlamından RegistrationForm örneği alıyoruz ve oradan özelliği doğrulamak için eklenen hizmeti kullanıyoruz. Bu doğrulamanın diğer özniteliklerde belirtilenlerin yanında yürütüleceğini unutmayın, bu nedenle özel doğrulama yöntemlerini ve mevcut doğrulama özniteliklerini istediğimiz gibi birleştirebiliriz.

Özel doğrulama öznitelikleri

Özel doğrulama yapmanın bir diğer yolu da özel [ValidationAttribute] bir uygulama yapmak ve ardından geçersiz kılınan IsValid yönteme doğrulama mantığını eklemektir. Bu, aynı özniteliği birden çok yerde yeniden kullanmanızı çok kolay hale getirdiğinden, yukarıda açıklanan yaklaşıma kıyasla daha fazla esneklik sağlar.

Bir özelliği, aynı görünüm modelindeki başka bir özelliğe göre göreli değerine göre doğrulamak istediğimizi varsayalım. İlk adım, aşağıdaki gibi özel [GreaterThanAttribute]bir tanımlamak olacaktır:

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");
    }
}

Daha sonra bu özniteliği viewmodelimize ekleyebiliriz:

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));
        }
    }
}

Bu durumda, belirli bir aralıkta ve aralarında belirli bir ilişkiye sahip olması gereken iki sayısal özelliğimiz vardır (A değerinden Bbüyük olması gerekir). Yeni [GreaterThanAttribute] öğesini ilk özelliğin üzerine ekledik; ayrıca, B için ayarlayıcıya ValidateProperty çağrısı da ekledik; böylece B her değiştiğinde A yeniden doğrulanır (çünkü doğrulama durumu buna bağlıdır). Bu özel doğrulamayı etkinleştirmek için görünüm modelimizdeki bu iki kod satırına ihtiyacımız var ve ayrıca uygulamamızdaki diğer görünüm modellerinde de yararlı olabilecek yeniden kullanılabilir bir özel doğrulama özniteliğine sahip olma avantajını elde ediyoruz. Doğrulama mantığı artık görünüm modeli tanımının kendisinden tamamen ayrılmış olduğundan bu yaklaşım kod modülerleştirmeye de yardımcı olur.

Örnekler