Skip to content

Commit 64ef7d3

Browse files
Fix issue with InputValidationAdorner not resolving once validation error has been fixed by user
Refactored logic into RefreshErrors method to be also used if INotifyDataErrorInfo context or property is dynamically changed as well.
1 parent b7637ca commit 64ef7d3

File tree

1 file changed

+39
-34
lines changed

1 file changed

+39
-34
lines changed

components/Adorners/src/InputValidation/InputValidationAdorner.cs

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
using System.Collections;
56
using System.ComponentModel.DataAnnotations;
67

78
using INotifyDataErrorInfo = System.ComponentModel.INotifyDataErrorInfo;
@@ -29,7 +30,7 @@ public string PropertyName
2930
/// Identifies the <see cref="PropertyName"/> dependency property.
3031
/// </summary>
3132
public static readonly DependencyProperty PropertyNameProperty =
32-
DependencyProperty.Register(nameof(PropertyName), typeof(string), typeof(InputValidationAdorner), new PropertyMetadata(null));
33+
DependencyProperty.Register(nameof(PropertyName), typeof(string), typeof(InputValidationAdorner), new PropertyMetadata(null, (s, e) => (s as InputValidationAdorner)?.RefreshErrors()));
3334

3435
/// <summary>
3536
/// Gets or sets the <see cref="INotifyDataErrorInfo"/> context object to use for validation.
@@ -44,7 +45,7 @@ public INotifyDataErrorInfo NotifyDataErrorInfo
4445
/// Identifies the <see cref="NotifyDataErrorInfo"/> dependency property.
4546
/// </summary>
4647
public static readonly DependencyProperty NotifyDataErrorInfoProperty =
47-
DependencyProperty.Register(nameof(NotifyDataErrorInfo), typeof(INotifyDataErrorInfo), typeof(InputValidationAdorner), new PropertyMetadata(null));
48+
DependencyProperty.Register(nameof(NotifyDataErrorInfo), typeof(INotifyDataErrorInfo), typeof(InputValidationAdorner), new PropertyMetadata(null, (s, e) => (s as InputValidationAdorner)?.RefreshErrors()));
4849

4950
/// <summary>
5051
/// Gets or sets whether the validation adorners is displayed (handled automatically).
@@ -76,6 +77,8 @@ public string ValidationMessage
7677
public static readonly DependencyProperty ValidationMessageProperty =
7778
DependencyProperty.Register(nameof(ValidationMessage), typeof(string), typeof(InputValidationAdorner), new PropertyMetadata(null));
7879

80+
// TODO: Do we consider an InfoBar style Severity property?
81+
7982
/// <summary>
8083
/// Initializes a new instance of the <see cref="InputValidationAdorner"/> class.
8184
/// </summary>
@@ -103,45 +106,47 @@ protected override void OnAttached()
103106

104107
private void INotifyDataErrorInfo_ErrorsChanged(object? sender, DataErrorsChangedEventArgs e)
105108
{
106-
if (NotifyDataErrorInfo is not null)
107-
{
108-
// Reset state
109-
if (!NotifyDataErrorInfo.HasErrors)
110-
{
111-
HasValidationFailed = false;
112-
ValidationMessage = string.Empty;
113-
return;
114-
}
109+
RefreshErrors();
110+
}
115111

116-
if (e.PropertyName == PropertyName)
112+
private void RefreshErrors()
113+
{
114+
// Check if we have any errors for our specified property
115+
if (NotifyDataErrorInfo is not null
116+
&& PropertyName is not null
117+
&& NotifyDataErrorInfo.GetErrors(PropertyName) is IEnumerable errors
118+
&& errors.Cast<object>().Any())
119+
{
120+
// Build up error messages depending on error collection type.
121+
StringBuilder message = new();
122+
if (errors is IEnumerable<ValidationResult> validationResults)
117123
{
118-
HasValidationFailed = true;
119-
120-
var errors = NotifyDataErrorInfo.GetErrors(e.PropertyName);
121-
122-
StringBuilder message = new();
123-
if (errors is IEnumerable<ValidationResult> validationResults)
124+
foreach (ValidationResult result in validationResults)
124125
{
125-
foreach (ValidationResult result in validationResults)
126-
{
127-
message.AppendLine(result.ErrorMessage);
128-
}
126+
message.AppendLine(result.ErrorMessage);
129127
}
130-
else if (errors is IEnumerable<string> stringErrors)
128+
}
129+
else if (errors is IEnumerable<string> stringErrors)
130+
{
131+
foreach (string result in stringErrors)
131132
{
132-
foreach (string result in stringErrors)
133-
{
134-
message.AppendLine(result);
135-
}
133+
message.AppendLine(result);
136134
}
137-
else
138-
{
139-
// TODO: Not sure if should handle more types of collections here?
140-
throw new ArgumentException("The errors returned by INotifyDataErrorInfo.GetErrors must be of type IEnumerable<ValidationResult> or IEnumerable<string>.");
141-
}
142-
143-
ValidationMessage = message.ToString().Trim();
144135
}
136+
else
137+
{
138+
// TODO: Not sure if should handle more types of collections here?
139+
throw new ArgumentException("The errors returned by INotifyDataErrorInfo.GetErrors must be of type IEnumerable<ValidationResult> or IEnumerable<string>.");
140+
}
141+
142+
HasValidationFailed = true;
143+
ValidationMessage = message.ToString().Trim();
144+
}
145+
else
146+
{
147+
// Hide if we have no object or errors to validate against.
148+
HasValidationFailed = false;
149+
ValidationMessage = string.Empty;
145150
}
146151
}
147152

0 commit comments

Comments
 (0)