Skip to content

Commit fefb499

Browse files
committed
Added custom ValidationContext to ObservableValidator
1 parent d70e6d9 commit fefb499

File tree

1 file changed

+41
-8
lines changed

1 file changed

+41
-8
lines changed

Microsoft.Toolkit.Mvvm/ComponentModel/ObservableValidator.cs

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ public abstract class ObservableValidator : ObservableObject, INotifyDataErrorIn
3030
/// </summary>
3131
private static readonly PropertyChangedEventArgs HasErrorsChangedEventArgs = new(nameof(HasErrors));
3232

33+
/// <summary>
34+
/// The <see cref="ValidationContext"/> instance currenty in use.
35+
/// </summary>
36+
private readonly ValidationContext validationContext;
37+
3338
/// <summary>
3439
/// The <see cref="Dictionary{TKey,TValue}"/> instance used to store previous validation results.
3540
/// </summary>
@@ -45,6 +50,36 @@ public abstract class ObservableValidator : ObservableObject, INotifyDataErrorIn
4550
/// <inheritdoc/>
4651
public event EventHandler<DataErrorsChangedEventArgs>? ErrorsChanged;
4752

53+
/// <summary>
54+
/// Initializes a new instance of the <see cref="ObservableValidator"/> class.
55+
/// This constructor will create a new <see cref="ValidationContext"/> that will
56+
/// be used to validate all properties, which will reference the current instance
57+
/// and no additional services or validation properties and settings.
58+
/// </summary>
59+
protected ObservableValidator()
60+
{
61+
this.validationContext = new ValidationContext(this);
62+
}
63+
64+
/// <summary>
65+
/// Initializes a new instance of the <see cref="ObservableValidator"/> class.
66+
/// This constructor will store the input <see cref="ValidationContext"/> instance,
67+
/// and it will use it to validate all properties for the current viewmodel.
68+
/// </summary>
69+
/// <param name="validationContext">
70+
/// The <see cref="ValidationContext"/> instance to use to validate properties.
71+
/// <para>
72+
/// This instance will be passed to all <see cref="Validator.TryValidateObject(object, ValidationContext, ICollection{ValidationResult})"/>
73+
/// calls executed by the current viewmodel, and its <see cref="ValidationContext.MemberName"/> property will be updated every time
74+
/// before the call is made to set the name of the property being validated. The property name will not be reset after that, so the
75+
/// value of <see cref="ValidationContext.MemberName"/> will always indicate the name of the last property that was validated, if any.
76+
/// </para>
77+
/// </param>
78+
protected ObservableValidator(ValidationContext validationContext)
79+
{
80+
this.validationContext = validationContext;
81+
}
82+
4883
/// <inheritdoc/>
4984
public bool HasErrors => this.totalErrors > 0;
5085

@@ -458,10 +493,9 @@ protected void ValidateProperty(object? value, [CallerMemberName] string? proper
458493
}
459494

460495
// Validate the property, by adding new errors to the existing list
461-
bool isValid = Validator.TryValidateProperty(
462-
value,
463-
new ValidationContext(this, null, null) { MemberName = propertyName },
464-
propertyErrors);
496+
this.validationContext.MemberName = propertyName;
497+
498+
bool isValid = Validator.TryValidateProperty(value, this.validationContext, propertyErrors);
465499

466500
// Update the shared counter for the number of errors, and raise the
467501
// property changed event if necessary. We decrement the number of total
@@ -529,10 +563,9 @@ private bool TryValidateProperty(object? value, string? propertyName, out IReadO
529563
List<ValidationResult> localErrors = new();
530564

531565
// Validate the property, by adding new errors to the local list
532-
bool isValid = Validator.TryValidateProperty(
533-
value,
534-
new ValidationContext(this, null, null) { MemberName = propertyName },
535-
localErrors);
566+
this.validationContext.MemberName = propertyName;
567+
568+
bool isValid = Validator.TryValidateProperty(value, this.validationContext, localErrors);
536569

537570
// We only modify the state if the property is valid and it wasn't so before. In this case, we
538571
// clear the cached list of errors (which is visible to consumers) and raise the necessary events.

0 commit comments

Comments
 (0)