BasicTests.cs 33 KB

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