ObservableValidator
인터페이스 ObservableValidator
를 구현하는 INotifyDataErrorInfo
기본 클래스로, 다른 애플리케이션 모듈에 노출된 속성의 유효성 검사를 지원합니다. 또한 상속되므로 ObservableObject
구현하고 INotifyPropertyChanging
구현합니다INotifyPropertyChanged
. 속성 변경 알림과 속성 유효성 검사를 모두 지원해야 하는 모든 종류의 개체에 대한 시작점으로 사용할 수 있습니다.
플랫폼 API: ObservableValidator, ObservableObject
작동 방식
ObservableValidator
에는 다음과 같은 주요 기능이 있습니다.
- 이벤트 및 기타 필요한 API를 노출하기
ErrorsChanged
위한INotifyDataErrorInfo
기본 구현을 제공합니다. - 기본
ObservableObject
클래스에서 제공하는 오버로드를 기반으로 하여 값을 업데이트하기 전에 속성의 유효성을 자동으로 검사하고 필요한 이벤트를 발생시키는 기능을 제공하는 일련의 추가SetProperty
오버로드를 제공합니다. - 유효성 검사에
TrySetProperty
성공한 경우에만 대상 속성을 업데이트하고 추가 검사를 위해SetProperty
생성된 오류(있는 경우)를 반환하는 기능과 유사하지만 여러 오버로드를 노출합니다. - 이 메서드는
ValidateProperty
해당 값이 업데이트되지 않았지만 유효성 검사가 대신 업데이트된 다른 속성의 값에 따라 달라지는 경우 특정 속성의 유효성 검사를 수동으로 트리거하는 데 유용할 수 있는 메서드를 노출합니다. - 이 메서드는
ValidateAllProperties
하나 이상[ValidationAttribute]
적용된 경우 현재 인스턴스의 모든 공용 인스턴스 속성에 대한 유효성 검사를 자동으로 실행하는 메서드를 노출합니다. - 사용자가 다시 입력할 수 있는 양식에 바인딩된 모델을 다시 설정할 때 유용할 수 있는 메서드를 노출
ClearAllErrors
합니다. - 다양한 매개 변수를 전달하여 속성의 유효성을 검사하는 데 사용할 인스턴스를
ValidationContext
초기화할 수 있는 여러 생성자를 제공합니다. 이는 추가 서비스 또는 옵션이 올바르게 작동해야 할 수 있는 사용자 지정 유효성 검사 특성을 사용할 때 특히 유용할 수 있습니다.
단순 속성
다음은 변경 알림과 유효성 검사를 모두 지원하는 속성을 구현하는 방법의 예입니다.
public class RegistrationForm : ObservableValidator
{
private string name;
[Required]
[MinLength(2)]
[MaxLength(100)]
public string Name
{
get => name;
set => SetProperty(ref name, value, true);
}
}
여기서는 해당 값이 업데이트될 ObservableValidator
때 속성의 SetProperty<T>(ref T, T, bool, string)
유효성을 검사할 것임을 나타내기 위해 true
추가 bool
매개 변수 집합을 통해 노출되는 메서드를 호출합니다. ObservableValidator
는 속성에 적용된 특성과 함께 지정된 모든 검사를 사용하여 모든 새 값에 대한 유효성 검사를 자동으로 실행합니다. 그런 다음 다른 구성 요소(예: UI 컨트롤)는 viewmodel과 상호 작용하고 뷰모델에 현재 존재하는 오류를 반영하도록 해당 상태를 수정할 수 있습니다. 이 메서드를 등록하고 메서드를 ErrorsChanged
사용하여 GetErrors(string)
수정된 각 속성에 대한 오류 목록을 검색합니다.
사용자 지정 유효성 검사 메서드
속성의 유효성을 검사하려면 viewmodel이 추가 서비스, 데이터 또는 기타 API에 액세스할 수 있어야 하는 경우가 있습니다. 시나리오 및 필요한 유연성 수준에 따라 속성에 사용자 지정 유효성 검사를 추가하는 방법에는 여러 가지가 있습니다. 다음은 속성의 추가 유효성 검사를 수행하기 위해 특정 메서드를 호출해야 함을 나타내는 데 형식을 사용하는 방법 [CustomValidationAttribute]
의 예입니다.
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");
}
}
이 경우 viewmodel에 삽입되는 서비스를 통해 속성에 대한 Name
유효성 검사를 수행하는 정적 ValidateName
메서드가 있습니다. 이 메서드는 name
viewmodel 인스턴스, 유효성을 검사할 속성의 이름, 선택적으로 서비스 공급자 및 ValidationContext
사용하거나 설정할 수 있는 일부 사용자 지정 플래그와 같은 항목을 포함하는 사용 중인 인스턴스와 속성 값을 받습니다. 이 경우 유효성 검사 컨텍스트에서 인스턴스를 RegistrationForm
검색하고 여기에서 삽입된 서비스를 사용하여 속성의 유효성을 검사합니다. 이 유효성 검사는 다른 특성에 지정된 특성 옆에 실행되므로 사용자 지정 유효성 검사 메서드와 기존 유효성 검사 특성을 자유롭게 결합할 수 있습니다.
사용자 지정 유효성 검사 특성
사용자 지정 유효성 검사를 수행하는 또 다른 방법은 사용자 지정 [ValidationAttribute]
을 구현한 다음 재정의된 메서드에 유효성 검사 논리를 IsValid
삽입하는 것입니다. 이렇게 하면 여러 위치에서 동일한 특성을 쉽게 재사용할 수 있으므로 위에서 설명한 접근 방식에 비해 유연성을 더할 수 있습니다.
동일한 viewmodel의 다른 속성과 관련하여 상대적 값을 기반으로 속성의 유효성을 검사하려고 했습니다. 첫 번째 단계는 다음과 같이 사용자 지정 [GreaterThanAttribute]
을 정의하는 것입니다.
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");
}
}
다음으로 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));
}
}
}
이 경우 특정 범위와 서로의 특정 관계(A
보다 B
커야 합니다)에 있어야 하는 두 개의 숫자 속성이 있습니다. 첫 번째 속성에 새 [GreaterThanAttribute]
속성을 추가했으며 setter에 대한 B
호출 ValidateProperty
도 추가했으므로 유효성 검사 상태가 따라 달라지므로 A
변경될 때마다 B
유효성이 다시 검사됩니다. 이 사용자 지정 유효성 검사를 사용하도록 설정하려면 viewmodel에서 이러한 두 줄의 코드만 있으면 되며, 애플리케이션의 다른 viewmodel에서도 유용할 수 있는 재사용 가능한 사용자 지정 유효성 검사 특성이 있다는 이점이 있습니다. 또한 이 방법은 유효성 검사 논리가 viewmodel 정의 자체에서 완전히 분리되므로 코드 모듈화에도 도움이 됩니다.
예제
- 샘플 앱(여러 UI 프레임워크의 경우)을 확인하여 작동 중인 MVVM 도구 키트를 확인합니다.
- 단위 테스트에서 더 많은 예제를 찾을 수도 있습니다.
MVVM Toolkit