@@ -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