Browse Source

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
pull/18767/head
drone 9 months ago
committed by GitHub
parent
commit
613760fcff
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 16
      src/Avalonia.Controls/DataValidationErrors.cs
  2. 22
      tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs

16
src/Avalonia.Controls/DataValidationErrors.cs

@ -18,7 +18,6 @@ namespace Avalonia.Controls
[PseudoClasses(":error")] [PseudoClasses(":error")]
public class DataValidationErrors : ContentControl public class DataValidationErrors : ContentControl
{ {
private static bool s_overridingErrors;
/// <summary> /// <summary>
/// Defines the DataValidationErrors.Errors attached property. /// Defines the DataValidationErrors.Errors attached property.
@ -49,6 +48,12 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
private static readonly AttachedProperty<IEnumerable<object>?> OriginalErrorsProperty = private static readonly AttachedProperty<IEnumerable<object>?> OriginalErrorsProperty =
AvaloniaProperty.RegisterAttached<DataValidationErrors, Control, IEnumerable<object>?>("OriginalErrors"); AvaloniaProperty.RegisterAttached<DataValidationErrors, Control, IEnumerable<object>?>("OriginalErrors");
/// <summary>
/// Prevents executing ErrorsChanged after they are updated internally from OnErrorsOrConverterChanged
/// </summary>
private static readonly AttachedProperty<bool> OverridingErrorsInternallyProperty =
AvaloniaProperty.RegisterAttached<DataValidationErrors, Control, bool>("OverridingErrorsInternally", defaultValue: false);
private Control? _owner; private Control? _owner;
@ -96,9 +101,10 @@ namespace Avalonia.Controls
private static void ErrorsChanged(AvaloniaPropertyChangedEventArgs e) private static void ErrorsChanged(AvaloniaPropertyChangedEventArgs e)
{ {
if (s_overridingErrors) return;
var control = (Control)e.Sender; var control = (Control)e.Sender;
if (control.GetValue(OverridingErrorsInternallyProperty)) return;
var errors = (IEnumerable<object>?)e.NewValue; var errors = (IEnumerable<object>?)e.NewValue;
// Update original errors // Update original errors
@ -140,14 +146,14 @@ namespace Avalonia.Controls
.Where(e => e is not null))? .Where(e => e is not null))?
.ToArray(); .ToArray();
s_overridingErrors = true; control.SetCurrentValue(OverridingErrorsInternallyProperty, true);
try try
{ {
control.SetCurrentValue(ErrorsProperty, newErrors!); control.SetCurrentValue(ErrorsProperty, newErrors!);
} }
finally finally
{ {
s_overridingErrors = false; control.SetCurrentValue(OverridingErrorsInternallyProperty, false);
} }
control.SetValue(HasErrorsProperty, newErrors?.Any() == true); control.SetValue(HasErrorsProperty, newErrors?.Any() == true);

22
tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs

@ -421,6 +421,28 @@ namespace Avalonia.Controls.UnitTests
}); });
} }
[Fact]
public void Text_Validation_TextBox_Errors_Binding()
{
RunTest((control, textbox) =>
{
// simulate the TemplateBinding that would be used within the AutoCompleteBox control theme for the inner PART_TextBox
// DataValidationErrors.Errors="{TemplateBinding (DataValidationErrors.Errors)}"
textbox.Bind(DataValidationErrors.ErrorsProperty, control.GetBindingObservable(DataValidationErrors.ErrorsProperty));
var exception = new InvalidCastException("failed validation");
var textObservable = new BehaviorSubject<BindingNotification>(new BindingNotification(exception, BindingErrorType.DataValidationError));
control.Bind(AutoCompleteBox.TextProperty, textObservable);
Dispatcher.UIThread.RunJobs();
Assert.True(DataValidationErrors.GetHasErrors(control));
Assert.Equal([exception], DataValidationErrors.GetErrors(control));
Assert.True(DataValidationErrors.GetHasErrors(textbox));
Assert.Equal([exception], DataValidationErrors.GetErrors(textbox));
});
}
[Fact] [Fact]
public void SelectedItem_Validation() public void SelectedItem_Validation()
{ {

Loading…
Cancel
Save