BasicTests.cs 33 KB

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