BindingTests.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. using System.Reactive.Subjects;
  2. using Avalonia.Controls;
  3. using Avalonia.UnitTests;
  4. using Xunit;
  5. namespace Avalonia.Markup.Xaml.UnitTests.Xaml
  6. {
  7. public class BindingTests : XamlTestBase
  8. {
  9. [Fact]
  10. public void Binding_To_DataContext_Works()
  11. {
  12. using (UnitTestApplication.Start(TestServices.StyledWindow))
  13. {
  14. var xaml = @"
  15. <Window xmlns='https://github.com/avaloniaui'
  16. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  17. xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'>
  18. <Button Name='button' Content='{Binding Foo}'/>
  19. </Window>";
  20. var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
  21. var button = window.FindControl<Button>("button");
  22. button.DataContext = new { Foo = "foo" };
  23. window.ApplyTemplate();
  24. Assert.Equal("foo", button.Content);
  25. }
  26. }
  27. [Fact]
  28. public void Longhand_Binding_To_DataContext_Works()
  29. {
  30. using (UnitTestApplication.Start(TestServices.StyledWindow))
  31. {
  32. var xaml = @"
  33. <Window xmlns='https://github.com/avaloniaui'
  34. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  35. xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'>
  36. <Button Name='button'>
  37. <Button.Content>
  38. <Binding Path='Foo'/>
  39. </Button.Content>
  40. </Button>
  41. </Window>";
  42. var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
  43. var button = window.FindControl<Button>("button");
  44. button.DataContext = new { Foo = "foo" };
  45. window.ApplyTemplate();
  46. Assert.Equal("foo", button.Content);
  47. }
  48. }
  49. [Fact]
  50. public void Can_Bind_Control_To_Non_Control()
  51. {
  52. using (UnitTestApplication.Start(TestServices.StyledWindow))
  53. {
  54. var xaml = @"
  55. <Window xmlns='https://github.com/avaloniaui'
  56. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  57. xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'>
  58. <Button Name='button' Content='Foo'>
  59. <Button.Tag>
  60. <local:NonControl Control='{Binding #button}'/>
  61. </Button.Tag>
  62. </Button>
  63. </Window>";
  64. var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
  65. var button = window.FindControl<Button>("button");
  66. Assert.Same(button, ((NonControl)button.Tag).Control);
  67. }
  68. }
  69. [Fact]
  70. public void Can_Bind_To_DataContext_Of_Anchor_On_Non_Control()
  71. {
  72. using (UnitTestApplication.Start(TestServices.MockWindowingPlatform))
  73. {
  74. var xaml = @"
  75. <Window xmlns='https://github.com/avaloniaui'
  76. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  77. xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'>
  78. <Button Name='button'>
  79. <Button.Tag>
  80. <local:NonControl String='{Binding Foo}'/>
  81. </Button.Tag>
  82. </Button>
  83. </Window>";
  84. var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
  85. var button = window.FindControl<Button>("button");
  86. button.DataContext = new { Foo = "foo" };
  87. Assert.Equal("foo", ((NonControl)button.Tag).String);
  88. }
  89. }
  90. [Fact]
  91. public void Binding_To_Window_Works()
  92. {
  93. using (UnitTestApplication.Start(TestServices.StyledWindow))
  94. {
  95. var xaml = @"
  96. <Window xmlns='https://github.com/avaloniaui'
  97. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  98. Title='{Binding Foo}'>
  99. </Window>";
  100. var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
  101. window.DataContext = new { Foo = "foo" };
  102. window.ApplyTemplate();
  103. Assert.Equal("foo", window.Title);
  104. }
  105. }
  106. [Fact]
  107. public void Binding_DataContext_To_Inherited_DataContext_Works()
  108. {
  109. using (UnitTestApplication.Start(TestServices.StyledWindow))
  110. {
  111. var xaml = @"
  112. <Window xmlns='https://github.com/avaloniaui'
  113. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  114. <Border DataContext='{Binding Foo}'/>
  115. </Window>";
  116. var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
  117. var border = (Border)window.Content;
  118. window.DataContext = new { Foo = "foo" };
  119. window.ApplyTemplate();
  120. window.Presenter.ApplyTemplate();
  121. Assert.Equal("foo", border.DataContext);
  122. }
  123. }
  124. [Fact]
  125. public void Binding_To_Self_Works()
  126. {
  127. using (UnitTestApplication.Start(TestServices.MockWindowingPlatform))
  128. {
  129. var xaml = @"
  130. <Window xmlns='https://github.com/avaloniaui'
  131. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  132. <TextBlock Name='textblock' Text='{Binding Tag, RelativeSource={RelativeSource Self}}'/>
  133. </Window>";
  134. var window = AvaloniaRuntimeXamlLoader.Parse<ContentControl>(xaml);
  135. var textBlock = (TextBlock)window.Content;
  136. textBlock.Tag = "foo";
  137. Assert.Equal("foo", textBlock.Text);
  138. }
  139. }
  140. [Fact]
  141. public void Longform_Binding_To_Self_Works()
  142. {
  143. using (UnitTestApplication.Start(TestServices.MockWindowingPlatform))
  144. {
  145. var xaml = @"
  146. <Window xmlns='https://github.com/avaloniaui'
  147. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  148. <TextBlock Name='textblock' Tag='foo'>
  149. <TextBlock.Text>
  150. <Binding RelativeSource='{RelativeSource Self}' Path='Tag'/>
  151. </TextBlock.Text>
  152. </TextBlock>
  153. </Window>";
  154. var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
  155. var textBlock = (TextBlock)window.Content;
  156. window.ApplyTemplate();
  157. Assert.Equal("foo", textBlock.Text);
  158. }
  159. }
  160. [Fact]
  161. public void Stream_Binding_To_Observable_Works()
  162. {
  163. using (UnitTestApplication.Start(TestServices.MockWindowingPlatform))
  164. {
  165. var xaml = @"
  166. <Window xmlns='https://github.com/avaloniaui'
  167. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  168. <TextBlock Name='textblock' Text='{Binding Observable^}'/>
  169. </Window>";
  170. var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
  171. var textBlock = (TextBlock)window.Content;
  172. var observable = new BehaviorSubject<string>("foo");
  173. window.DataContext = new { Observable = observable };
  174. window.ApplyTemplate();
  175. Assert.Equal("foo", textBlock.Text);
  176. observable.OnNext("bar");
  177. Assert.Equal("bar", textBlock.Text);
  178. }
  179. }
  180. [Fact]
  181. public void Binding_To_Namespaced_Attached_Property_Works()
  182. {
  183. using (UnitTestApplication.Start(TestServices.MockWindowingPlatform))
  184. {
  185. var xaml = @"
  186. <Window xmlns='https://github.com/avaloniaui'
  187. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  188. xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'>
  189. <TextBlock local:AttachedPropertyOwner.Double='{Binding}'/>
  190. </Window>";
  191. var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
  192. var textBlock = (TextBlock)window.Content;
  193. window.DataContext = 5.6;
  194. window.ApplyTemplate();
  195. Assert.Equal(5.6, AttachedPropertyOwner.GetDouble(textBlock));
  196. }
  197. }
  198. [Fact]
  199. public void Binding_To_AddOwnered_Attached_Property_Works()
  200. {
  201. using (UnitTestApplication.Start(TestServices.MockWindowingPlatform))
  202. {
  203. var xaml = @"
  204. <Window xmlns='https://github.com/avaloniaui'
  205. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  206. xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'>
  207. <local:TestControl Double='{Binding}'/>
  208. </Window>";
  209. var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
  210. var testControl = (TestControl)window.Content;
  211. window.DataContext = 5.6;
  212. window.ApplyTemplate();
  213. Assert.Equal(5.6, testControl.Double);
  214. }
  215. }
  216. [Fact]
  217. public void Binding_To_Attached_Property_Using_AddOwnered_Type_Works()
  218. {
  219. using (UnitTestApplication.Start(TestServices.MockWindowingPlatform))
  220. {
  221. var xaml = @"
  222. <Window xmlns='https://github.com/avaloniaui'
  223. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  224. xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'>
  225. <TextBlock local:TestControl.Double='{Binding}'/>
  226. </Window>";
  227. var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
  228. var textBlock = (TextBlock)window.Content;
  229. window.DataContext = 5.6;
  230. window.ApplyTemplate();
  231. Assert.Equal(5.6, AttachedPropertyOwner.GetDouble(textBlock));
  232. }
  233. }
  234. [Fact]
  235. public void Binding_To_Attached_Property_In_Style_Works()
  236. {
  237. using (UnitTestApplication.Start(TestServices.StyledWindow))
  238. {
  239. var xaml = @"
  240. <Window xmlns='https://github.com/avaloniaui'
  241. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  242. xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'>
  243. <Window.Styles>
  244. <Style Selector='TextBlock'>
  245. <Setter Property='local:TestControl.Double' Value='{Binding}'/>
  246. </Style>
  247. </Window.Styles>
  248. <TextBlock/>
  249. </Window>";
  250. var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
  251. var textBlock = (TextBlock)window.Content;
  252. window.DataContext = 5.6;
  253. window.ApplyTemplate();
  254. Assert.Equal(5.6, AttachedPropertyOwner.GetDouble(textBlock));
  255. }
  256. }
  257. [Theory,
  258. InlineData(@"Hello \{0\}"),
  259. InlineData(@"'Hello {0}'"),
  260. InlineData(@"Hello {0}")]
  261. public void Binding_To_TextBlock_Text_With_StringConverter_Works(string fmt)
  262. {
  263. using (UnitTestApplication.Start(TestServices.StyledWindow))
  264. {
  265. var xaml = @"
  266. <Window xmlns='https://github.com/avaloniaui'
  267. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  268. xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'>
  269. <TextBlock Name='textBlock' Text=""{Binding Foo, StringFormat=" + fmt + @"}""/>
  270. </Window>";
  271. var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
  272. var textBlock = window.FindControl<TextBlock>("textBlock");
  273. textBlock.DataContext = new { Foo = "world" };
  274. window.ApplyTemplate();
  275. Assert.Equal("Hello world", textBlock.Text);
  276. }
  277. }
  278. [Theory,
  279. InlineData("{}{0} {1}!"),
  280. InlineData(@"\{0\} \{1\}!")]
  281. public void MultiBinding_To_TextBlock_Text_With_StringConverter_Works(string fmt)
  282. {
  283. using (UnitTestApplication.Start(TestServices.StyledWindow))
  284. {
  285. var xaml = @"
  286. <Window xmlns='https://github.com/avaloniaui'
  287. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  288. xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'>
  289. <TextBlock Name='textBlock'>
  290. <TextBlock.Text>
  291. <MultiBinding StringFormat='" + fmt + @"'>
  292. <Binding Path='Greeting1'/>
  293. <Binding Path='Greeting2'/>
  294. </MultiBinding>
  295. </TextBlock.Text>
  296. </TextBlock>
  297. </Window>";
  298. var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
  299. var textBlock = window.FindControl<TextBlock>("textBlock");
  300. textBlock.DataContext = new WindowViewModel();
  301. window.ApplyTemplate();
  302. Assert.Equal("Hello World!", textBlock.Text);
  303. }
  304. }
  305. [Fact]
  306. public void Binding_OneWayToSource_Works()
  307. {
  308. using (UnitTestApplication.Start(TestServices.StyledWindow))
  309. {
  310. var xaml = @"
  311. <Window xmlns='https://github.com/avaloniaui'
  312. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  313. ShowInTaskbar='{Binding ShowInTaskbar, Mode=OneWayToSource}'>
  314. </Window>";
  315. var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
  316. var viewModel = new WindowViewModel();
  317. window.DataContext = viewModel;
  318. window.ApplyTemplate();
  319. Assert.True(window.ShowInTaskbar);
  320. Assert.True(viewModel.ShowInTaskbar);
  321. }
  322. }
  323. private class WindowViewModel
  324. {
  325. public bool ShowInTaskbar { get; set; }
  326. public string Greeting1 { get; set; } = "Hello";
  327. public string Greeting2 { get; set; } = "World";
  328. }
  329. }
  330. }