AvaloniaObjectTests_DataValidation.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reactive.Subjects;
  5. using Avalonia.Data;
  6. using Avalonia.UnitTests;
  7. using Xunit;
  8. namespace Avalonia.Base.UnitTests
  9. {
  10. public class AvaloniaObjectTests_DataValidation
  11. {
  12. [Fact]
  13. public void Binding_Non_Validated_Styled_Property_Does_Not_Call_UpdateDataValidation()
  14. {
  15. var target = new Class1();
  16. var source = new Subject<BindingValue<int>>();
  17. target.Bind(Class1.NonValidatedProperty, source);
  18. source.OnNext(6);
  19. source.OnNext(BindingValue<int>.BindingError(new Exception()));
  20. source.OnNext(BindingValue<int>.DataValidationError(new Exception()));
  21. source.OnNext(6);
  22. Assert.Empty(target.Notifications);
  23. }
  24. [Fact]
  25. public void Binding_Non_Validated_Direct_Property_Does_Not_Call_UpdateDataValidation()
  26. {
  27. var target = new Class1();
  28. var source = new Subject<BindingValue<int>>();
  29. target.Bind(Class1.NonValidatedDirectProperty, source);
  30. source.OnNext(6);
  31. source.OnNext(BindingValue<int>.BindingError(new Exception()));
  32. source.OnNext(BindingValue<int>.DataValidationError(new Exception()));
  33. source.OnNext(6);
  34. Assert.Empty(target.Notifications);
  35. }
  36. [Fact]
  37. public void Binding_Validated_Direct_Property_Calls_UpdateDataValidation()
  38. {
  39. var target = new Class1();
  40. var source = new Subject<BindingValue<int>>();
  41. target.Bind(Class1.ValidatedDirectIntProperty, source);
  42. source.OnNext(6);
  43. source.OnNext(BindingValue<int>.BindingError(new Exception()));
  44. source.OnNext(BindingValue<int>.DataValidationError(new Exception()));
  45. source.OnNext(7);
  46. var result = target.Notifications;
  47. Assert.Equal(4, result.Count);
  48. Assert.Equal(BindingValueType.Value, result[0].type);
  49. Assert.Equal(6, result[0].value);
  50. Assert.Equal(BindingValueType.BindingError, result[1].type);
  51. Assert.Equal(BindingValueType.DataValidationError, result[2].type);
  52. Assert.Equal(BindingValueType.Value, result[3].type);
  53. Assert.Equal(7, result[3].value);
  54. }
  55. [Fact]
  56. public void Binding_Overridden_Validated_Direct_Property_Calls_UpdateDataValidation()
  57. {
  58. var target = new Class2();
  59. var source = new Subject<BindingValue<int>>();
  60. // Class2 overrides `NonValidatedDirectProperty`'s metadata to enable data validation.
  61. target.Bind(Class1.NonValidatedDirectProperty, source);
  62. source.OnNext(1);
  63. Assert.Equal(1, target.Notifications.Count);
  64. }
  65. [Fact]
  66. public void Bound_Validated_Direct_String_Property_Can_Be_Set_To_Null()
  67. {
  68. var source = new ViewModel
  69. {
  70. StringValue = "foo",
  71. };
  72. var target = new Class1
  73. {
  74. [!Class1.ValidatedDirectStringProperty] = new Binding
  75. {
  76. Path = nameof(ViewModel.StringValue),
  77. Source = source,
  78. },
  79. };
  80. Assert.Equal("foo", target.ValidatedDirectString);
  81. source.StringValue = null;
  82. Assert.Null(target.ValidatedDirectString);
  83. }
  84. private class Class1 : AvaloniaObject
  85. {
  86. public static readonly StyledProperty<int> NonValidatedProperty =
  87. AvaloniaProperty.Register<Class1, int>(
  88. nameof(NonValidated));
  89. public static readonly DirectProperty<Class1, int> NonValidatedDirectProperty =
  90. AvaloniaProperty.RegisterDirect<Class1, int>(
  91. nameof(NonValidatedDirect),
  92. o => o.NonValidatedDirect,
  93. (o, v) => o.NonValidatedDirect = v);
  94. public static readonly DirectProperty<Class1, int> ValidatedDirectIntProperty =
  95. AvaloniaProperty.RegisterDirect<Class1, int>(
  96. nameof(ValidatedDirectInt),
  97. o => o.ValidatedDirectInt,
  98. (o, v) => o.ValidatedDirectInt = v,
  99. enableDataValidation: true);
  100. public static readonly DirectProperty<Class1, string> ValidatedDirectStringProperty =
  101. AvaloniaProperty.RegisterDirect<Class1, string>(
  102. nameof(ValidatedDirectString),
  103. o => o.ValidatedDirectString,
  104. (o, v) => o.ValidatedDirectString = v,
  105. enableDataValidation: true);
  106. private int _nonValidatedDirect;
  107. private int _directInt;
  108. private string _directString;
  109. public int NonValidated
  110. {
  111. get { return GetValue(NonValidatedProperty); }
  112. set { SetValue(NonValidatedProperty, value); }
  113. }
  114. public int NonValidatedDirect
  115. {
  116. get { return _directInt; }
  117. set { SetAndRaise(NonValidatedDirectProperty, ref _nonValidatedDirect, value); }
  118. }
  119. public int ValidatedDirectInt
  120. {
  121. get { return _directInt; }
  122. set { SetAndRaise(ValidatedDirectIntProperty, ref _directInt, value); }
  123. }
  124. public string ValidatedDirectString
  125. {
  126. get { return _directString; }
  127. set { SetAndRaise(ValidatedDirectStringProperty, ref _directString, value); }
  128. }
  129. public List<(BindingValueType type, object value)> Notifications { get; } = new();
  130. protected override void UpdateDataValidation(
  131. AvaloniaProperty property,
  132. BindingValueType state,
  133. Exception error)
  134. {
  135. Notifications.Add((state, GetValue(property)));
  136. }
  137. }
  138. private class Class2 : Class1
  139. {
  140. static Class2()
  141. {
  142. NonValidatedDirectProperty.OverrideMetadata<Class2>(
  143. new DirectPropertyMetadata<int>(enableDataValidation: true));
  144. }
  145. }
  146. public class ViewModel : NotifyingBase
  147. {
  148. private string _stringValue;
  149. public string StringValue
  150. {
  151. get { return _stringValue; }
  152. set { _stringValue = value; RaisePropertyChanged(); }
  153. }
  154. }
  155. }
  156. }