BasicTests.cs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953
  1. // Copyright (c) The Avalonia Project. All rights reserved.
  2. // Licensed under the MIT license. See licence.md file in the project root for full license information.
  3. using Avalonia.Collections;
  4. using Avalonia.Controls;
  5. using Avalonia.Controls.Presenters;
  6. using Avalonia.Markup.Xaml.Data;
  7. using Avalonia.Markup.Xaml.Styling;
  8. using Avalonia.Markup.Xaml.Templates;
  9. using Avalonia.Media;
  10. using Avalonia.Media.Immutable;
  11. using Avalonia.Styling;
  12. using Avalonia.UnitTests;
  13. using Portable.Xaml;
  14. using System.Collections;
  15. using System.ComponentModel;
  16. using System.Linq;
  17. using Xunit;
  18. namespace Avalonia.Markup.Xaml.UnitTests.Xaml
  19. {
  20. public class BasicTests
  21. {
  22. [Fact]
  23. public void Simple_Property_Is_Set()
  24. {
  25. var xaml = @"<ContentControl xmlns='https://github.com/avaloniaui' Content='Foo'/>";
  26. var target = AvaloniaXamlLoader.Parse<ContentControl>(xaml);
  27. Assert.NotNull(target);
  28. Assert.Equal("Foo", target.Content);
  29. }
  30. [Fact]
  31. public void Default_Content_Property_Is_Set()
  32. {
  33. var xaml = @"<ContentControl xmlns='https://github.com/avaloniaui'>Foo</ContentControl>";
  34. var target = AvaloniaXamlLoader.Parse<ContentControl>(xaml);
  35. Assert.NotNull(target);
  36. Assert.Equal("Foo", target.Content);
  37. }
  38. [Fact]
  39. public void AvaloniaProperty_Without_Getter_And_Setter_Is_Set()
  40. {
  41. var xaml =
  42. @"<local:NonControl xmlns='https://github.com/avaloniaui'
  43. xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'
  44. Foo='55' />";
  45. var target = AvaloniaXamlLoader.Parse<NonControl>(xaml);
  46. Assert.Equal(55, target.GetValue(NonControl.FooProperty));
  47. }
  48. [Fact]
  49. public void AvaloniaProperty_With_Getter_And_No_Setter_Is_Set()
  50. {
  51. var xaml =
  52. @"<local:NonControl xmlns='https://github.com/avaloniaui'
  53. xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'
  54. Bar='bar' />";
  55. var target = AvaloniaXamlLoader.Parse<NonControl>(xaml);
  56. Assert.Equal("bar", target.Bar);
  57. }
  58. [Fact]
  59. public void Attached_Property_Is_Set()
  60. {
  61. var xaml =
  62. @"<ContentControl xmlns='https://github.com/avaloniaui' TextBlock.FontSize='21'/>";
  63. var target = AvaloniaXamlLoader.Parse<ContentControl>(xaml);
  64. Assert.NotNull(target);
  65. Assert.Equal(21.0, TextBlock.GetFontSize(target));
  66. }
  67. [Fact]
  68. public void Attached_Property_Is_Set_On_Control_Outside_Avalonia_Namspace()
  69. {
  70. // Test for issue #1548
  71. var xaml =
  72. @"<UserControl xmlns='https://github.com/avaloniaui'
  73. xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'>
  74. <local:TestControl Grid.Column='2' />
  75. </UserControl>";
  76. var target = AvaloniaXamlLoader.Parse<UserControl>(xaml);
  77. Assert.Equal(2, Grid.GetColumn((TestControl)target.Content));
  78. }
  79. [Fact]
  80. public void Attached_Property_With_Namespace_Is_Set()
  81. {
  82. var xaml =
  83. @"<ContentControl xmlns='https://github.com/avaloniaui'
  84. xmlns:test='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'
  85. test:BasicTestsAttachedPropertyHolder.Foo='Bar'/>";
  86. var target = AvaloniaXamlLoader.Parse<ContentControl>(xaml);
  87. Assert.NotNull(target);
  88. Assert.Equal("Bar", BasicTestsAttachedPropertyHolder.GetFoo(target));
  89. }
  90. [Fact]
  91. public void Attached_Property_Supports_Binding()
  92. {
  93. using (UnitTestApplication.Start(TestServices.MockWindowingPlatform))
  94. {
  95. var xaml =
  96. @"<Window xmlns='https://github.com/avaloniaui' TextBlock.FontSize='{Binding}'/>";
  97. var target = AvaloniaXamlLoader.Parse<ContentControl>(xaml);
  98. target.DataContext = 21.0;
  99. Assert.Equal(21.0, TextBlock.GetFontSize(target));
  100. }
  101. }
  102. [Fact]
  103. public void Attached_Property_In_Panel_Is_Set()
  104. {
  105. var xaml = @"
  106. <Panel xmlns='https://github.com/avaloniaui'>
  107. <ToolTip.Tip>Foo</ToolTip.Tip>
  108. </Panel>";
  109. var target = AvaloniaXamlLoader.Parse<Panel>(xaml);
  110. Assert.Empty(target.Children);
  111. Assert.Equal("Foo", ToolTip.GetTip(target));
  112. }
  113. [Fact]
  114. public void NonExistent_Property_Throws()
  115. {
  116. var xaml =
  117. @"<ContentControl xmlns='https://github.com/avaloniaui' DoesntExist='foo'/>";
  118. Assert.Throws<XamlObjectWriterException>(() => AvaloniaXamlLoader.Parse<ContentControl>(xaml));
  119. }
  120. [Fact]
  121. public void Non_Attached_Property_With_Attached_Property_Syntax_Throws()
  122. {
  123. var xaml =
  124. @"<ContentControl xmlns='https://github.com/avaloniaui' TextBlock.Text='foo'/>";
  125. Assert.Throws<XamlObjectWriterException>(() => AvaloniaXamlLoader.Parse<ContentControl>(xaml));
  126. }
  127. [Fact]
  128. public void ContentControl_ContentTemplate_Is_Functional()
  129. {
  130. var xaml =
  131. @"<ContentControl xmlns='https://github.com/avaloniaui'>
  132. <ContentControl.ContentTemplate>
  133. <DataTemplate>
  134. <TextBlock Text='Foo' />
  135. </DataTemplate>
  136. </ContentControl.ContentTemplate>
  137. </ContentControl>";
  138. var contentControl = AvaloniaXamlLoader.Parse<ContentControl>(xaml);
  139. var target = contentControl.ContentTemplate;
  140. Assert.NotNull(target);
  141. var txt = (TextBlock)target.Build(null);
  142. Assert.Equal("Foo", txt.Text);
  143. }
  144. [Fact]
  145. public void Named_Control_Is_Added_To_NameScope_Simple()
  146. {
  147. var xaml = @"
  148. <UserControl xmlns='https://github.com/avaloniaui'>
  149. <Button Name='button'>Foo</Button>
  150. </UserControl>";
  151. var control = AvaloniaXamlLoader.Parse<UserControl>(xaml);
  152. var button = control.FindControl<Button>("button");
  153. Assert.Equal("Foo", button.Content);
  154. }
  155. [Fact]
  156. public void Direct_Content_In_ItemsControl_Is_Operational()
  157. {
  158. using (UnitTestApplication.Start(TestServices.StyledWindow))
  159. {
  160. var xaml = @"
  161. <Window xmlns='https://github.com/avaloniaui'>
  162. <ItemsControl Name='items'>
  163. <ContentControl>Foo</ContentControl>
  164. <ContentControl>Bar</ContentControl>
  165. </ItemsControl>
  166. </Window>";
  167. var control = AvaloniaXamlLoader.Parse<Window>(xaml);
  168. var itemsControl = control.FindControl<ItemsControl>("items");
  169. Assert.NotNull(itemsControl);
  170. var items = itemsControl.Items.Cast<ContentControl>().ToArray();
  171. Assert.Equal("Foo", items[0].Content);
  172. Assert.Equal("Bar", items[1].Content);
  173. }
  174. }
  175. [Fact]
  176. public void Panel_Children_Are_Added()
  177. {
  178. var xaml = @"
  179. <UserControl xmlns='https://github.com/avaloniaui'>
  180. <Panel Name='panel'>
  181. <ContentControl Name='Foo' />
  182. <ContentControl Name='Bar' />
  183. </Panel>
  184. </UserControl>";
  185. var control = AvaloniaXamlLoader.Parse<UserControl>(xaml);
  186. var panel = control.FindControl<Panel>("panel");
  187. Assert.Equal(2, panel.Children.Count);
  188. var foo = control.FindControl<ContentControl>("Foo");
  189. var bar = control.FindControl<ContentControl>("Bar");
  190. Assert.Contains(foo, panel.Children);
  191. Assert.Contains(bar, panel.Children);
  192. }
  193. [Fact]
  194. public void Grid_Row_Col_Definitions_Are_Built()
  195. {
  196. var xaml = @"
  197. <Grid xmlns='https://github.com/avaloniaui'>
  198. <Grid.ColumnDefinitions>
  199. <ColumnDefinition Width='100' />
  200. <ColumnDefinition Width='Auto' />
  201. <ColumnDefinition Width='*' />
  202. <ColumnDefinition Width='100*' />
  203. </Grid.ColumnDefinitions>
  204. <Grid.RowDefinitions>
  205. <RowDefinition Height='100' />
  206. <RowDefinition Height='Auto' />
  207. <RowDefinition Height='*' />
  208. <RowDefinition Height='100*' />
  209. </Grid.RowDefinitions>
  210. </Grid>";
  211. var grid = AvaloniaXamlLoader.Parse<Grid>(xaml);
  212. Assert.Equal(4, grid.ColumnDefinitions.Count);
  213. Assert.Equal(4, grid.RowDefinitions.Count);
  214. var expected1 = new GridLength(100);
  215. var expected2 = GridLength.Auto;
  216. var expected3 = new GridLength(1, GridUnitType.Star);
  217. var expected4 = new GridLength(100, GridUnitType.Star);
  218. Assert.Equal(expected1, grid.ColumnDefinitions[0].Width);
  219. Assert.Equal(expected2, grid.ColumnDefinitions[1].Width);
  220. Assert.Equal(expected3, grid.ColumnDefinitions[2].Width);
  221. Assert.Equal(expected4, grid.ColumnDefinitions[3].Width);
  222. Assert.Equal(expected1, grid.RowDefinitions[0].Height);
  223. Assert.Equal(expected2, grid.RowDefinitions[1].Height);
  224. Assert.Equal(expected3, grid.RowDefinitions[2].Height);
  225. Assert.Equal(expected4, grid.RowDefinitions[3].Height);
  226. }
  227. [Fact]
  228. public void Grid_Row_Col_Definitions_Are_Parsed()
  229. {
  230. var xaml = @"
  231. <Grid xmlns='https://github.com/avaloniaui'
  232. ColumnDefinitions='100,Auto,*,100*'
  233. RowDefinitions='100,Auto,*,100*'>
  234. </Grid>";
  235. var grid = AvaloniaXamlLoader.Parse<Grid>(xaml);
  236. Assert.Equal(4, grid.ColumnDefinitions.Count);
  237. Assert.Equal(4, grid.RowDefinitions.Count);
  238. var expected1 = new GridLength(100);
  239. var expected2 = GridLength.Auto;
  240. var expected3 = new GridLength(1, GridUnitType.Star);
  241. var expected4 = new GridLength(100, GridUnitType.Star);
  242. Assert.Equal(expected1, grid.ColumnDefinitions[0].Width);
  243. Assert.Equal(expected2, grid.ColumnDefinitions[1].Width);
  244. Assert.Equal(expected3, grid.ColumnDefinitions[2].Width);
  245. Assert.Equal(expected4, grid.ColumnDefinitions[3].Width);
  246. Assert.Equal(expected1, grid.RowDefinitions[0].Height);
  247. Assert.Equal(expected2, grid.RowDefinitions[1].Height);
  248. Assert.Equal(expected3, grid.RowDefinitions[2].Height);
  249. Assert.Equal(expected4, grid.RowDefinitions[3].Height);
  250. }
  251. [Fact]
  252. public void ControlTemplate_With_Nested_Child_Is_Operational()
  253. {
  254. var xaml = @"
  255. <ControlTemplate xmlns='https://github.com/avaloniaui'>
  256. <ContentControl Name='parent'>
  257. <ContentControl Name='child' />
  258. </ContentControl>
  259. </ControlTemplate>
  260. ";
  261. var template = AvaloniaXamlLoader.Parse<ControlTemplate>(xaml);
  262. var parent = (ContentControl)template.Build(new ContentControl());
  263. Assert.Equal("parent", parent.Name);
  264. var child = parent.Content as ContentControl;
  265. Assert.NotNull(child);
  266. Assert.Equal("child", child.Name);
  267. }
  268. [Fact]
  269. public void ControlTemplate_With_Panel_Children_Are_Added()
  270. {
  271. var xaml = @"
  272. <ControlTemplate xmlns='https://github.com/avaloniaui'>
  273. <Panel Name='panel'>
  274. <ContentControl Name='Foo' />
  275. <ContentControl Name='Bar' />
  276. </Panel>
  277. </ControlTemplate>
  278. ";
  279. var template = AvaloniaXamlLoader.Parse<ControlTemplate>(xaml);
  280. var panel = (Panel)template.Build(new ContentControl());
  281. Assert.Equal(2, panel.Children.Count);
  282. var foo = panel.Children[0];
  283. var bar = panel.Children[1];
  284. Assert.Equal("Foo", foo.Name);
  285. Assert.Equal("Bar", bar.Name);
  286. }
  287. [Fact]
  288. public void Named_x_Control_Is_Added_To_NameScope_Simple()
  289. {
  290. var xaml = @"
  291. <UserControl xmlns='https://github.com/avaloniaui'
  292. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  293. <Button x:Name='button'>Foo</Button>
  294. </UserControl>";
  295. var control = AvaloniaXamlLoader.Parse<UserControl>(xaml);
  296. var button = control.FindControl<Button>("button");
  297. Assert.Equal("Foo", button.Content);
  298. }
  299. [Fact]
  300. public void Standart_TypeConverter_Is_Used()
  301. {
  302. var xaml = @"<UserControl xmlns='https://github.com/avaloniaui' Width='200.5' />";
  303. var control = AvaloniaXamlLoader.Parse<UserControl>(xaml);
  304. Assert.Equal(200.5, control.Width);
  305. }
  306. [Fact]
  307. public void Avalonia_TypeConverter_Is_Used()
  308. {
  309. var xaml = @"<UserControl xmlns='https://github.com/avaloniaui' Background='White' />";
  310. var control = AvaloniaXamlLoader.Parse<UserControl>(xaml);
  311. var bk = control.Background;
  312. Assert.IsType<ImmutableSolidColorBrush>(bk);
  313. Assert.Equal(Colors.White, (bk as ISolidColorBrush).Color);
  314. }
  315. [Fact]
  316. public void Simple_Style_Is_Parsed()
  317. {
  318. var xaml = @"
  319. <Styles xmlns='https://github.com/avaloniaui'
  320. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  321. <Style Selector='TextBlock'>
  322. <Setter Property='Background' Value='White'/>
  323. <Setter Property='Width' Value='100'/>
  324. </Style>
  325. </Styles>";
  326. var styles = AvaloniaXamlLoader.Parse<Styles>(xaml);
  327. Assert.Single(styles);
  328. var style = (Style)styles[0];
  329. var setters = style.Setters.Cast<Setter>().ToArray();
  330. Assert.Equal(2, setters.Length);
  331. Assert.Equal(TextBlock.BackgroundProperty, setters[0].Property);
  332. Assert.Equal(Brushes.White.Color, ((ISolidColorBrush)setters[0].Value).Color);
  333. Assert.Equal(TextBlock.WidthProperty, setters[1].Property);
  334. Assert.Equal(100.0, setters[1].Value);
  335. }
  336. [Fact]
  337. public void Style_Setter_With_AttachedProperty_Is_Parsed()
  338. {
  339. var xaml = @"
  340. <Styles xmlns='https://github.com/avaloniaui'
  341. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  342. <Style Selector='ContentControl'>
  343. <Setter Property='TextBlock.FontSize' Value='21'/>
  344. </Style>
  345. </Styles>";
  346. var styles = AvaloniaXamlLoader.Parse<Styles>(xaml);
  347. Assert.Single(styles);
  348. var style = (Style)styles[0];
  349. var setters = style.Setters.Cast<Setter>().ToArray();
  350. Assert.Single(setters);
  351. Assert.Equal(TextBlock.FontSizeProperty, setters[0].Property);
  352. Assert.Equal(21.0, setters[0].Value);
  353. }
  354. [Fact]
  355. public void Complex_Style_Is_Parsed()
  356. {
  357. using (UnitTestApplication.Start(TestServices.StyledWindow))
  358. {
  359. var xaml = @"
  360. <Styles xmlns='https://github.com/avaloniaui'>
  361. <Style Selector='CheckBox'>
  362. <Setter Property='BorderBrush' Value='{DynamicResource ThemeBorderMidBrush}'/>
  363. <Setter Property='BorderThickness' Value='{DynamicResource ThemeBorderThickness}'/>
  364. <Setter Property='Template'>
  365. <ControlTemplate>
  366. <Grid ColumnDefinitions='Auto,*'>
  367. <Border Name='border'
  368. BorderBrush='{TemplateBinding BorderBrush}'
  369. BorderThickness='{TemplateBinding BorderThickness}'
  370. Width='18'
  371. Height='18'
  372. VerticalAlignment='Center'>
  373. <Path Name='checkMark'
  374. Fill='{StaticResource HighlightBrush}'
  375. Width='11'
  376. Height='10'
  377. Stretch='Uniform'
  378. HorizontalAlignment='Center'
  379. VerticalAlignment='Center'
  380. Data='M 1145.607177734375,430 C1145.607177734375,430 1141.449951171875,435.0772705078125 1141.449951171875,435.0772705078125 1141.449951171875,435.0772705078125 1139.232177734375,433.0999755859375 1139.232177734375,433.0999755859375 1139.232177734375,433.0999755859375 1138,434.5538330078125 1138,434.5538330078125 1138,434.5538330078125 1141.482177734375,438 1141.482177734375,438 1141.482177734375,438 1141.96875,437.9375 1141.96875,437.9375 1141.96875,437.9375 1147,431.34619140625 1147,431.34619140625 1147,431.34619140625 1145.607177734375,430 1145.607177734375,430 z'/>
  381. </Border>
  382. <ContentPresenter Name='PART_ContentPresenter'
  383. Content='{TemplateBinding Content}'
  384. ContentTemplate='{TemplateBinding ContentTemplate}'
  385. Margin='4,0,0,0'
  386. VerticalAlignment='Center'
  387. Grid.Column='1'/>
  388. </Grid>
  389. </ControlTemplate>
  390. </Setter>
  391. </Style>
  392. </Styles>
  393. ";
  394. var styles = AvaloniaXamlLoader.Parse<Styles>(xaml);
  395. Assert.Single(styles);
  396. var style = (Style)styles[0];
  397. var setters = style.Setters.Cast<Setter>().ToArray();
  398. Assert.Equal(3, setters.Length);
  399. Assert.Equal(CheckBox.BorderBrushProperty, setters[0].Property);
  400. Assert.Equal(CheckBox.BorderThicknessProperty, setters[1].Property);
  401. Assert.Equal(CheckBox.TemplateProperty, setters[2].Property);
  402. Assert.IsType<ControlTemplate>(setters[2].Value);
  403. }
  404. }
  405. [Fact]
  406. public void Style_Resources_Are_Built()
  407. {
  408. var xaml = @"
  409. <Style xmlns='https://github.com/avaloniaui'
  410. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  411. xmlns:sys='clr-namespace:System;assembly=mscorlib'>
  412. <Style.Resources>
  413. <SolidColorBrush x:Key='Brush'>White</SolidColorBrush>
  414. <sys:Double x:Key='Double'>10</sys:Double>
  415. </Style.Resources>
  416. </Style>";
  417. var style = AvaloniaXamlLoader.Parse<Style>(xaml);
  418. Assert.True(style.Resources.Count > 0);
  419. style.TryGetResource("Brush", out var brush);
  420. Assert.NotNull(brush);
  421. Assert.Equal(Colors.White, ((ISolidColorBrush)brush).Color);
  422. style.TryGetResource("Double", out var d);
  423. Assert.Equal(10.0, d);
  424. }
  425. [Fact]
  426. public void StyleInclude_Is_Built()
  427. {
  428. using (UnitTestApplication.Start(TestServices.StyledWindow))
  429. {
  430. var xaml = @"
  431. <Styles xmlns='https://github.com/avaloniaui'
  432. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  433. <StyleInclude Source='resm:Avalonia.Themes.Default.ContextMenu.xaml?assembly=Avalonia.Themes.Default'/>
  434. </Styles>";
  435. var styles = AvaloniaXamlLoader.Parse<Styles>(xaml);
  436. Assert.True(styles.Count == 1);
  437. var styleInclude = styles.First() as StyleInclude;
  438. Assert.NotNull(styleInclude);
  439. var style = styleInclude.Loaded;
  440. Assert.NotNull(style);
  441. }
  442. }
  443. [Fact]
  444. public void Simple_Xaml_Binding_Is_Operational()
  445. {
  446. using (UnitTestApplication.Start(TestServices.MockPlatformWrapper
  447. .With(windowingPlatform: new MockWindowingPlatform())))
  448. {
  449. var xaml =
  450. @"<Window xmlns='https://github.com/avaloniaui' Content='{Binding}'/>";
  451. var target = AvaloniaXamlLoader.Parse<ContentControl>(xaml);
  452. Assert.Null(target.Content);
  453. target.DataContext = "Foo";
  454. Assert.Equal("Foo", target.Content);
  455. }
  456. }
  457. [Fact]
  458. public void Xaml_Binding_Is_Delayed()
  459. {
  460. using (UnitTestApplication.Start(TestServices.MockWindowingPlatform))
  461. {
  462. var xaml =
  463. @"<ContentControl xmlns='https://github.com/avaloniaui' Content='{Binding}'/>";
  464. var target = AvaloniaXamlLoader.Parse<ContentControl>(xaml);
  465. Assert.Null(target.Content);
  466. target.DataContext = "Foo";
  467. Assert.Null(target.Content);
  468. DelayedBinding.ApplyBindings(target);
  469. Assert.Equal("Foo", target.Content);
  470. }
  471. }
  472. [Fact]
  473. public void Double_Xaml_Binding_Is_Operational()
  474. {
  475. using (UnitTestApplication.Start(TestServices.MockPlatformWrapper
  476. .With(windowingPlatform: new MockWindowingPlatform())))
  477. {
  478. var xaml =
  479. @"<Window xmlns='https://github.com/avaloniaui' Width='{Binding}'/>";
  480. var target = AvaloniaXamlLoader.Parse<ContentControl>(xaml);
  481. Assert.Null(target.Content);
  482. target.DataContext = 55.0;
  483. Assert.Equal(55.0, target.Width);
  484. }
  485. }
  486. [Fact]
  487. public void Collection_Xaml_Binding_Is_Operational()
  488. {
  489. using (UnitTestApplication.Start(TestServices.MockPlatformWrapper
  490. .With(windowingPlatform: new MockWindowingPlatform())))
  491. {
  492. var xaml = @"
  493. <Window xmlns='https://github.com/avaloniaui'>
  494. <ItemsControl Name='itemsControl' Items='{Binding}'>
  495. </ItemsControl>
  496. </Window>
  497. ";
  498. var target = AvaloniaXamlLoader.Parse<Window>(xaml);
  499. Assert.NotNull(target.Content);
  500. var itemsControl = target.FindControl<ItemsControl>("itemsControl");
  501. var items = new string[] { "Foo", "Bar" };
  502. //DelayedBinding.ApplyBindings(itemsControl);
  503. target.DataContext = items;
  504. Assert.Equal(items, itemsControl.Items);
  505. }
  506. }
  507. [Fact]
  508. public void Multi_Xaml_Binding_Is_Parsed()
  509. {
  510. var xaml =
  511. @"<MultiBinding xmlns='https://github.com/avaloniaui' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  512. Converter ='{x:Static BoolConverters.And}'>
  513. <Binding Path='Foo' />
  514. <Binding Path='Bar' />
  515. </MultiBinding>";
  516. var target = AvaloniaXamlLoader.Parse<MultiBinding>(xaml);
  517. Assert.Equal(2, target.Bindings.Count);
  518. Assert.Equal(BoolConverters.And, target.Converter);
  519. var bindings = target.Bindings.Cast<Binding>().ToArray();
  520. Assert.Equal("Foo", bindings[0].Path);
  521. Assert.Equal("Bar", bindings[1].Path);
  522. }
  523. [Fact]
  524. public void Control_Template_Is_Operational()
  525. {
  526. using (UnitTestApplication.Start(TestServices.MockPlatformWrapper
  527. .With(windowingPlatform: new MockWindowingPlatform())))
  528. {
  529. var xaml = @"
  530. <Window xmlns='https://github.com/avaloniaui'
  531. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  532. <Window.Template>
  533. <ControlTemplate>
  534. <ContentPresenter Name='PART_ContentPresenter'
  535. Content='{TemplateBinding Content}'/>
  536. </ControlTemplate>
  537. </Window.Template>
  538. </Window>";
  539. var target = AvaloniaXamlLoader.Parse<ContentControl>(xaml);
  540. Assert.NotNull(target.Template);
  541. Assert.Null(target.Presenter);
  542. target.ApplyTemplate();
  543. Assert.NotNull(target.Presenter);
  544. target.Content = "Foo";
  545. Assert.Equal("Foo", target.Presenter.Content);
  546. }
  547. }
  548. [Fact]
  549. public void Style_ControlTemplate_Is_Built()
  550. {
  551. var xaml = @"
  552. <Style xmlns='https://github.com/avaloniaui' Selector='ContentControl'>
  553. <Setter Property='Template'>
  554. <ControlTemplate>
  555. <ContentPresenter Name='PART_ContentPresenter'
  556. Content='{TemplateBinding Content}'
  557. ContentTemplate='{TemplateBinding ContentTemplate}' />
  558. </ControlTemplate>
  559. </Setter>
  560. </Style> ";
  561. var style = AvaloniaXamlLoader.Parse<Style>(xaml);
  562. Assert.Single(style.Setters);
  563. var setter = (Setter)style.Setters.First();
  564. Assert.Equal(ContentControl.TemplateProperty, setter.Property);
  565. Assert.IsType<ControlTemplate>(setter.Value);
  566. var template = (ControlTemplate)setter.Value;
  567. var control = new ContentControl();
  568. var result = (ContentPresenter)template.Build(control);
  569. Assert.NotNull(result);
  570. }
  571. [Fact]
  572. public void Named_Control_Is_Added_To_NameScope()
  573. {
  574. using (UnitTestApplication.Start(TestServices.StyledWindow))
  575. {
  576. var xaml = @"
  577. <Window xmlns='https://github.com/avaloniaui'
  578. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  579. <Button Name='button'>Foo</Button>
  580. </Window>";
  581. var window = AvaloniaXamlLoader.Parse<Window>(xaml);
  582. var button = window.FindControl<Button>("button");
  583. Assert.Equal("Foo", button.Content);
  584. }
  585. }
  586. [Fact(Skip =
  587. @"Doesn't work with Portable.xaml, it's working in different creation order -
  588. Handled in test 'Control_Is_Added_To_Parent_Before_Final_EndInit'
  589. do we need it?")]
  590. public void Control_Is_Added_To_Parent_Before_Properties_Are_Set()
  591. {
  592. using (UnitTestApplication.Start(TestServices.StyledWindow))
  593. {
  594. var xaml = @"
  595. <Window xmlns='https://github.com/avaloniaui'
  596. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  597. xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'>
  598. <local:InitializationOrderTracker Width='100'/>
  599. </Window>";
  600. var window = AvaloniaXamlLoader.Parse<Window>(xaml);
  601. var tracker = (InitializationOrderTracker)window.Content;
  602. var attached = tracker.Order.IndexOf("AttachedToLogicalTree");
  603. var widthChanged = tracker.Order.IndexOf("Property Width Changed");
  604. Assert.NotEqual(-1, attached);
  605. Assert.NotEqual(-1, widthChanged);
  606. Assert.True(attached < widthChanged);
  607. }
  608. }
  609. [Fact]
  610. public void Control_Is_Added_To_Parent_Before_Final_EndInit()
  611. {
  612. using (UnitTestApplication.Start(TestServices.StyledWindow))
  613. {
  614. var xaml = @"
  615. <Window xmlns='https://github.com/avaloniaui'
  616. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  617. xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'>
  618. <local:InitializationOrderTracker Width='100'/>
  619. </Window>";
  620. var window = AvaloniaXamlLoader.Parse<Window>(xaml);
  621. var tracker = (InitializationOrderTracker)window.Content;
  622. var attached = tracker.Order.IndexOf("AttachedToLogicalTree");
  623. var endInit = tracker.Order.IndexOf("EndInit 0");
  624. Assert.NotEqual(-1, attached);
  625. Assert.NotEqual(-1, endInit);
  626. Assert.True(attached < endInit);
  627. }
  628. }
  629. [Fact]
  630. public void All_Properties_Are_Set_Before_Final_EndInit()
  631. {
  632. using (UnitTestApplication.Start(TestServices.StyledWindow))
  633. {
  634. var xaml = @"
  635. <Window xmlns='https://github.com/avaloniaui'
  636. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  637. xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'>
  638. <local:InitializationOrderTracker Width='100' Height='100'
  639. Tag='{Binding Height, RelativeSource={RelativeSource Self}}' />
  640. </Window>";
  641. var window = AvaloniaXamlLoader.Parse<Window>(xaml);
  642. var tracker = (InitializationOrderTracker)window.Content;
  643. //ensure binding is set and operational first
  644. Assert.Equal(100.0, tracker.Tag);
  645. Assert.Equal("EndInit 0", tracker.Order.Last());
  646. }
  647. }
  648. [Fact]
  649. public void BeginInit_Matches_EndInit()
  650. {
  651. using (UnitTestApplication.Start(TestServices.StyledWindow))
  652. {
  653. var xaml = @"
  654. <Window xmlns='https://github.com/avaloniaui'
  655. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  656. xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'>
  657. <local:InitializationOrderTracker />
  658. </Window>";
  659. var window = AvaloniaXamlLoader.Parse<Window>(xaml);
  660. var tracker = (InitializationOrderTracker)window.Content;
  661. Assert.Equal(0, tracker.InitState);
  662. }
  663. }
  664. [Fact]
  665. public void DeferedXamlLoader_Should_Preserve_NamespacesContext()
  666. {
  667. var xaml =
  668. @"<ContentControl xmlns='https://github.com/avaloniaui'
  669. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  670. xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'>
  671. <ContentControl.ContentTemplate>
  672. <DataTemplate>
  673. <TextBlock Tag='{x:Static local:NonControl.StringProperty}'/>
  674. </DataTemplate>
  675. </ContentControl.ContentTemplate>
  676. </ContentControl>";
  677. var contentControl = AvaloniaXamlLoader.Parse<ContentControl>(xaml);
  678. var template = contentControl.ContentTemplate;
  679. Assert.NotNull(template);
  680. var txt = (TextBlock)template.Build(null);
  681. Assert.Equal((object)NonControl.StringProperty, txt.Tag);
  682. }
  683. [Fact]
  684. public void Binding_To_List_AvaloniaProperty_Is_Operational()
  685. {
  686. using (UnitTestApplication.Start(TestServices.MockWindowingPlatform))
  687. {
  688. var xaml = @"
  689. <Window xmlns='https://github.com/avaloniaui'>
  690. <ListBox Items='{Binding Items}' SelectedItems='{Binding SelectedItems}'/>
  691. </Window>";
  692. var window = AvaloniaXamlLoader.Parse<Window>(xaml);
  693. var listBox = (ListBox)window.Content;
  694. var vm = new SelectedItemsViewModel()
  695. {
  696. Items = new string[] { "foo", "bar", "baz" }
  697. };
  698. window.DataContext = vm;
  699. Assert.Equal(vm.Items, listBox.Items);
  700. Assert.Equal(vm.SelectedItems, listBox.SelectedItems);
  701. }
  702. }
  703. [Fact]
  704. public void Element_Whitespace_Should_Be_Trimmed()
  705. {
  706. using (UnitTestApplication.Start(TestServices.MockWindowingPlatform))
  707. {
  708. var xaml = @"
  709. <Window xmlns='https://github.com/avaloniaui'>
  710. <TextBlock>
  711. Hello World!
  712. </TextBlock>
  713. </Window>";
  714. var window = AvaloniaXamlLoader.Parse<Window>(xaml);
  715. var textBlock = (TextBlock)window.Content;
  716. Assert.Equal("Hello World!", textBlock.Text);
  717. }
  718. }
  719. private class SelectedItemsViewModel : INotifyPropertyChanged
  720. {
  721. public string[] Items { get; set; }
  722. public event PropertyChangedEventHandler PropertyChanged;
  723. private IList _selectedItems = new AvaloniaList<string>();
  724. public IList SelectedItems
  725. {
  726. get { return _selectedItems; }
  727. set
  728. {
  729. _selectedItems = value;
  730. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelectedItems)));
  731. }
  732. }
  733. }
  734. }
  735. public class BasicTestsAttachedPropertyHolder
  736. {
  737. public static AvaloniaProperty<string> FooProperty =
  738. AvaloniaProperty.RegisterAttached<BasicTestsAttachedPropertyHolder, AvaloniaObject, string>("Foo");
  739. public static void SetFoo(AvaloniaObject target, string value) => target.SetValue(FooProperty, value);
  740. public static string GetFoo(AvaloniaObject target) => (string)target.GetValue(FooProperty);
  741. }
  742. }