Skip to content

Commit 340c98d

Browse files
drone1400MrJul
authored andcommitted
Fixes for DataValidationErrors not working correctly with Bindings (issue #18693) (#18694)
* Added unit test for AutoCompleteBox DataValidationErrors - checks that when the TextBox control's Errors are bound to the parent AutoCompleteBox, they get updated correctly in both parent AutoCompleteBox control and TextBox control * Fix issue with DataValidationErrors causing issues with AutoCompleteBox because of Bindings - when binding a control's DataValidationErrors.Errors property to the same property of another control, the use of a static bool flag "s_overridingErrors" was preventing the control with the Binding from being updated correctly - issue is resolved by replacing static bool flag with a private AttachedProperty<bool> in DataValidationErrors.cs * Clean up Asserts in previous AutoCompleteBoxTests.cs changes
1 parent 2dfce79 commit 340c98d

File tree

2 files changed

+33
-5
lines changed

2 files changed

+33
-5
lines changed

src/Avalonia.Controls/DataValidationErrors.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ namespace Avalonia.Controls
1818
[PseudoClasses(":error")]
1919
public class DataValidationErrors : ContentControl
2020
{
21-
private static bool s_overridingErrors;
2221

2322
/// <summary>
2423
/// Defines the DataValidationErrors.Errors attached property.
@@ -49,6 +48,12 @@ public class DataValidationErrors : ContentControl
4948
/// </summary>
5049
private static readonly AttachedProperty<IEnumerable<object>?> OriginalErrorsProperty =
5150
AvaloniaProperty.RegisterAttached<DataValidationErrors, Control, IEnumerable<object>?>("OriginalErrors");
51+
52+
/// <summary>
53+
/// Prevents executing ErrorsChanged after they are updated internally from OnErrorsOrConverterChanged
54+
/// </summary>
55+
private static readonly AttachedProperty<bool> OverridingErrorsInternallyProperty =
56+
AvaloniaProperty.RegisterAttached<DataValidationErrors, Control, bool>("OverridingErrorsInternally", defaultValue: false);
5257

5358
private Control? _owner;
5459

@@ -96,9 +101,10 @@ public IDataTemplate ErrorTemplate
96101

97102
private static void ErrorsChanged(AvaloniaPropertyChangedEventArgs e)
98103
{
99-
if (s_overridingErrors) return;
100-
101104
var control = (Control)e.Sender;
105+
106+
if (control.GetValue(OverridingErrorsInternallyProperty)) return;
107+
102108
var errors = (IEnumerable<object>?)e.NewValue;
103109

104110
// Update original errors
@@ -140,14 +146,14 @@ private static void OnErrorsOrConverterChanged(Control control)
140146
.Where(e => e is not null))?
141147
.ToArray();
142148

143-
s_overridingErrors = true;
149+
control.SetCurrentValue(OverridingErrorsInternallyProperty, true);
144150
try
145151
{
146152
control.SetCurrentValue(ErrorsProperty, newErrors!);
147153
}
148154
finally
149155
{
150-
s_overridingErrors = false;
156+
control.SetCurrentValue(OverridingErrorsInternallyProperty, false);
151157
}
152158

153159
control.SetValue(HasErrorsProperty, newErrors?.Any() == true);

tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,28 @@ public void Text_Validation()
421421
});
422422
}
423423

424+
[Fact]
425+
public void Text_Validation_TextBox_Errors_Binding()
426+
{
427+
RunTest((control, textbox) =>
428+
{
429+
// simulate the TemplateBinding that would be used within the AutoCompleteBox control theme for the inner PART_TextBox
430+
// DataValidationErrors.Errors="{TemplateBinding (DataValidationErrors.Errors)}"
431+
textbox.Bind(DataValidationErrors.ErrorsProperty, control.GetBindingObservable(DataValidationErrors.ErrorsProperty));
432+
433+
var exception = new InvalidCastException("failed validation");
434+
var textObservable = new BehaviorSubject<BindingNotification>(new BindingNotification(exception, BindingErrorType.DataValidationError));
435+
control.Bind(AutoCompleteBox.TextProperty, textObservable);
436+
Dispatcher.UIThread.RunJobs();
437+
438+
Assert.True(DataValidationErrors.GetHasErrors(control));
439+
Assert.Equal([exception], DataValidationErrors.GetErrors(control));
440+
441+
Assert.True(DataValidationErrors.GetHasErrors(textbox));
442+
Assert.Equal([exception], DataValidationErrors.GetErrors(textbox));
443+
});
444+
}
445+
424446
[Fact]
425447
public void SelectedItem_Validation()
426448
{

0 commit comments

Comments
 (0)