BindingExpressionTests.SetValue.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. using System;
  2. using System.Globalization;
  3. using Avalonia.Controls;
  4. using Avalonia.Data;
  5. using Avalonia.Data.Converters;
  6. using Avalonia.UnitTests;
  7. using Xunit;
  8. #nullable enable
  9. namespace Avalonia.Base.UnitTests.Data.Core;
  10. public abstract partial class BindingExpressionTests
  11. {
  12. [Fact]
  13. public void Should_Write_Value_To_Source()
  14. {
  15. var data = new ViewModel { StringValue = "foo" };
  16. var target = CreateTargetWithSource(data, o => o.StringValue, mode: BindingMode.TwoWay);
  17. target.String = "bar";
  18. Assert.Equal("bar", data.StringValue);
  19. }
  20. [Fact]
  21. public void Should_Write_Value_To_Attached_Property_On_Source()
  22. {
  23. var data = new AvaloniaObject();
  24. var target = CreateTargetWithSource(
  25. data,
  26. o => o[DockPanel.DockProperty],
  27. mode: BindingMode.TwoWay,
  28. targetProperty: Control.TagProperty);
  29. target.Tag = Dock.Right;
  30. Assert.Equal(Dock.Right, data[DockPanel.DockProperty]);
  31. }
  32. [Fact]
  33. public void Should_Write_Indexed_Value_To_Source()
  34. {
  35. var data = new { Foo = new[] { "foo" } };
  36. var target = CreateTargetWithSource(data, o => o.Foo[0], mode: BindingMode.TwoWay);
  37. target.String = "bar";
  38. Assert.Equal("bar", data.Foo[0]);
  39. GC.KeepAlive(data);
  40. }
  41. [Fact]
  42. public void Should_Write_Value_To_Source_On_Simple_Property_Chain()
  43. {
  44. var data = new ViewModel { Next = new() { StringValue = "foo" } };
  45. var target = CreateTargetWithSource(data, o => o.Next!.StringValue, mode: BindingMode.TwoWay);
  46. target.String = "bar";
  47. Assert.Equal("bar", data.Next!.StringValue);
  48. }
  49. [Fact]
  50. public void Target_Value_Can_Be_Set_On_Broken_Chain()
  51. {
  52. var data = new ViewModel { Next = new() { StringValue = "foo" } };
  53. var target = CreateTargetWithSource(data, o => o.Next!.StringValue, mode: BindingMode.TwoWay);
  54. data.Next = null;
  55. target.String = "bar";
  56. Assert.Equal("bar", target.String);
  57. }
  58. [Fact]
  59. public void Should_Use_Converter_When_Writing_To_Source()
  60. {
  61. var data = new ViewModel { StringValue = "foo" };
  62. var target = CreateTargetWithSource(
  63. data,
  64. o => o.StringValue,
  65. mode: BindingMode.TwoWay,
  66. converter: new CaseConverter());
  67. target.String = "BaR";
  68. Assert.Equal("bar", data.StringValue);
  69. GC.KeepAlive(data);
  70. }
  71. [Fact]
  72. public void TwoWay_Binding_Should_Not_Write_Unchanged_Value_Back_To_Property_With_Converter()
  73. {
  74. var data = new Cat();
  75. var target = CreateTargetWithSource(
  76. data,
  77. o => o.WhiskerCount,
  78. converter: new CaseConverter(),
  79. mode: BindingMode.TwoWay);
  80. Assert.Equal(4, target.Int);
  81. Assert.Equal(9, data.Lives);
  82. data.WhiskerCount = 3;
  83. Assert.Equal(3, target.Int);
  84. Assert.Equal(8, data.Lives);
  85. GC.KeepAlive(data);
  86. }
  87. [Fact]
  88. public void Setter_Should_Convert_Double_To_String()
  89. {
  90. var data = new ViewModel { StringValue = $"{5.6}" };
  91. var target = CreateTargetWithSource(
  92. data,
  93. o => o.StringValue,
  94. mode: BindingMode.TwoWay,
  95. targetProperty: TargetClass.DoubleProperty);
  96. target.Double = 6.7;
  97. Assert.Equal($"{6.7}", data.StringValue);
  98. GC.KeepAlive(data);
  99. }
  100. [Fact]
  101. public void Setter_Should_Convert_String_To_Double()
  102. {
  103. var data = new ViewModel { DoubleValue = 5.6 };
  104. var target = CreateTargetWithSource(
  105. data,
  106. o => o.DoubleValue,
  107. mode: BindingMode.TwoWay,
  108. targetProperty: TargetClass.StringProperty);
  109. target.String = $"{6.7}";
  110. Assert.Equal(6.7, data.DoubleValue);
  111. GC.KeepAlive(data);
  112. }
  113. [Fact]
  114. public void Setting_Invalid_Double_String_Should_Not_Change_Target()
  115. {
  116. var data = new ViewModel { DoubleValue = 5.6 };
  117. var target = CreateTargetWithSource(
  118. data,
  119. o => o.DoubleValue,
  120. mode: BindingMode.TwoWay,
  121. targetProperty: TargetClass.StringProperty);
  122. target.String = "foo";
  123. Assert.Equal(5.6, data.DoubleValue);
  124. GC.KeepAlive(data);
  125. }
  126. [Fact]
  127. public void Setting_Invalid_Double_String_Should_Use_FallbackValue()
  128. {
  129. var data = new ViewModel { DoubleValue = 5.6 };
  130. var target = CreateTargetWithSource(
  131. data,
  132. o => o.DoubleValue,
  133. mode: BindingMode.TwoWay,
  134. fallbackValue: 9.8,
  135. targetProperty: TargetClass.StringProperty);
  136. target.String = "foo";
  137. Assert.Equal(9.8, data.DoubleValue);
  138. GC.KeepAlive(data);
  139. }
  140. [Fact]
  141. public void Should_Pass_ConverterParameter_To_Converter_ConvertBack()
  142. {
  143. var data = new ViewModel { StringValue = "Initial" };
  144. var converter = new PrefixConverter();
  145. var target = CreateTargetWithSource(
  146. data,
  147. o => o.StringValue,
  148. converter: converter,
  149. converterParameter: "foo",
  150. mode: BindingMode.TwoWay);
  151. target.String = "fooBar";
  152. Assert.Equal("Bar", data.StringValue);
  153. }
  154. private class Cat : NotifyingBase
  155. {
  156. private int _whiskerCount = 4;
  157. public int WhiskerCount
  158. {
  159. get => _whiskerCount;
  160. set
  161. {
  162. _whiskerCount = value;
  163. RaisePropertyChanged(nameof(WhiskerCount));
  164. --Lives;
  165. }
  166. }
  167. public int Lives { get; private set; } = 9;
  168. }
  169. private class CaseConverter : IValueConverter
  170. {
  171. public static readonly CaseConverter Instance = new();
  172. public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
  173. {
  174. return value?.ToString()?.ToUpper();
  175. }
  176. public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
  177. {
  178. return value?.ToString()?.ToLower();
  179. }
  180. }
  181. }