Skip to content

Commit 69b133c

Browse files
committed
Tweaked ObservableValidator constructors, added tests
1 parent fefb499 commit 69b133c

File tree

2 files changed

+72
-0
lines changed

2 files changed

+72
-0
lines changed

Microsoft.Toolkit.Mvvm/ComponentModel/ObservableValidator.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,29 @@ protected ObservableValidator()
6161
this.validationContext = new ValidationContext(this);
6262
}
6363

64+
/// <summary>
65+
/// Initializes a new instance of the <see cref="ObservableValidator"/> class.
66+
/// This constructor will create a new <see cref="ValidationContext"/> that will
67+
/// be used to validate all properties, which will reference the current instance.
68+
/// </summary>
69+
/// <param name="items">A set of key/value pairs to make available to consumers.</param>
70+
protected ObservableValidator(IDictionary<object, object> items)
71+
{
72+
this.validationContext = new ValidationContext(this, items);
73+
}
74+
75+
/// <summary>
76+
/// Initializes a new instance of the <see cref="ObservableValidator"/> class.
77+
/// This constructor will create a new <see cref="ValidationContext"/> that will
78+
/// be used to validate all properties, which will reference the current instance.
79+
/// </summary>
80+
/// <param name="serviceProvider">An <see cref="IServiceProvider"/> instance to make available during validation.</param>
81+
/// <param name="items">A set of key/value pairs to make available to consumers.</param>
82+
protected ObservableValidator(IServiceProvider serviceProvider, IDictionary<object, object> items)
83+
{
84+
this.validationContext = new ValidationContext(this, serviceProvider, items);
85+
}
86+
6487
/// <summary>
6588
/// Initializes a new instance of the <see cref="ObservableValidator"/> class.
6689
/// This constructor will store the input <see cref="ValidationContext"/> instance,

UnitTests/UnitTests.Shared/Mvvm/Test_ObservableValidator.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,22 @@ public void Test_ObservableValidator_ValidateAllProperties()
339339
Assert.IsTrue(events.Any(e => e.PropertyName == nameof(Person.Age)));
340340
}
341341

342+
[TestCategory("Mvvm")]
343+
[TestMethod]
344+
public void Test_ObservableValidator_CustomValidation()
345+
{
346+
var items = new Dictionary<object, object> { [nameof(CustomValidationModel.A)] = 42 };
347+
var model = new CustomValidationModel(items);
348+
var events = new List<DataErrorsChangedEventArgs>();
349+
350+
model.ErrorsChanged += (s, e) => events.Add(e);
351+
352+
model.A = 10;
353+
354+
Assert.IsFalse(model.HasErrors);
355+
Assert.AreEqual(events.Count, 0);
356+
}
357+
342358
public class Person : ObservableValidator
343359
{
344360
private string name;
@@ -444,5 +460,38 @@ protected override ValidationResult IsValid(object value, ValidationContext vali
444460
return new ValidationResult("The current value is smaller than the other one");
445461
}
446462
}
463+
464+
/// <summary>
465+
/// Test model for custom validation properties.
466+
/// See https://github.com/windows-toolkit/WindowsCommunityToolkit/issues/3729 for the original request for this feature.
467+
/// </summary>
468+
public class CustomValidationModel : ObservableValidator
469+
{
470+
public CustomValidationModel(IDictionary<object, object> items)
471+
: base(items)
472+
{
473+
}
474+
475+
private int a;
476+
477+
[CustomValidation(typeof(CustomValidationModel), nameof(ValidateA))]
478+
public int A
479+
{
480+
get => this.a;
481+
set => SetProperty(ref this.a, value, true);
482+
}
483+
484+
public static ValidationResult ValidateA(int x, ValidationContext context)
485+
{
486+
Assert.AreEqual(context.MemberName, nameof(A));
487+
488+
if ((int)context.Items[nameof(A)] == 42)
489+
{
490+
return ValidationResult.Success;
491+
}
492+
493+
return new ValidationResult("Missing the magic number");
494+
}
495+
}
447496
}
448497
}

0 commit comments

Comments
 (0)