BasicTests.cs 33 KB

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