BasicTests.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  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.Controls;
  4. using Avalonia.Controls.Presenters;
  5. using Avalonia.Markup.Xaml.Data;
  6. using Avalonia.Markup.Xaml.Styling;
  7. using Avalonia.Markup.Xaml.Templates;
  8. using Avalonia.Media;
  9. using Avalonia.Styling;
  10. using Avalonia.UnitTests;
  11. using System.Linq;
  12. using Xunit;
  13. namespace Avalonia.Markup.Xaml.UnitTests.Xaml
  14. {
  15. public class BasicTests
  16. {
  17. [Fact]
  18. public void Simple_Property_Is_Set()
  19. {
  20. var xaml = @"<ContentControl xmlns='https://github.com/avaloniaui' Content='Foo'/>";
  21. var target = AvaloniaXamlLoader.Parse<ContentControl>(xaml);
  22. Assert.NotNull(target);
  23. Assert.Equal("Foo", target.Content);
  24. }
  25. [Fact]
  26. public void Default_Content_Property_Is_Set()
  27. {
  28. var xaml = @"<ContentControl xmlns='https://github.com/avaloniaui'>Foo</ContentControl>";
  29. var target = AvaloniaXamlLoader.Parse<ContentControl>(xaml);
  30. Assert.NotNull(target);
  31. Assert.Equal("Foo", target.Content);
  32. }
  33. [Fact]
  34. public void Attached_Property_Is_Set()
  35. {
  36. var xaml =
  37. @"<ContentControl xmlns='https://github.com/avaloniaui' TextBlock.FontSize='21'/>";
  38. var target = AvaloniaXamlLoader.Parse<ContentControl>(xaml);
  39. Assert.NotNull(target);
  40. Assert.Equal(21.0, TextBlock.GetFontSize(target));
  41. }
  42. [Fact]
  43. public void Attached_Property_In_Panel_Is_Set()
  44. {
  45. var xaml = @"
  46. <Panel xmlns='https://github.com/avaloniaui'>
  47. <ToolTip.Tip>Foo</ToolTip.Tip>
  48. </Panel>";
  49. var target = AvaloniaXamlLoader.Parse<Panel>(xaml);
  50. Assert.Equal(0, target.Children.Count);
  51. Assert.Equal("Foo", ToolTip.GetTip(target));
  52. }
  53. [Fact]
  54. public void ContentControl_ContentTemplate_Is_Functional()
  55. {
  56. var xaml =
  57. @"<ContentControl xmlns='https://github.com/avaloniaui'>
  58. <ContentControl.ContentTemplate>
  59. <DataTemplate>
  60. <TextBlock Text='Foo' />
  61. </DataTemplate>
  62. </ContentControl.ContentTemplate>
  63. </ContentControl>";
  64. var contentControl = AvaloniaXamlLoader.Parse<ContentControl>(xaml);
  65. var target = contentControl.ContentTemplate;
  66. Assert.NotNull(target);
  67. var txt = (TextBlock)target.Build(null);
  68. Assert.Equal("Foo", txt.Text);
  69. }
  70. [Fact]
  71. public void Named_Control_Is_Added_To_NameScope_Simple()
  72. {
  73. var xaml = @"
  74. <UserControl xmlns='https://github.com/avaloniaui'>
  75. <Button Name='button'>Foo</Button>
  76. </UserControl>";
  77. var control = AvaloniaXamlLoader.Parse<UserControl>(xaml);
  78. var button = control.FindControl<Button>("button");
  79. Assert.Equal("Foo", button.Content);
  80. }
  81. [Fact]
  82. public void Panel_Children_Are_Added()
  83. {
  84. var xaml = @"
  85. <UserControl xmlns='https://github.com/avaloniaui'>
  86. <Panel Name='panel'>
  87. <ContentControl Name='Foo' />
  88. <ContentControl Name='Bar' />
  89. </Panel>
  90. </UserControl>";
  91. var control = AvaloniaXamlLoader.Parse<UserControl>(xaml);
  92. var panel = control.FindControl<Panel>("panel");
  93. Assert.Equal(2, panel.Children.Count);
  94. var foo = control.FindControl<ContentControl>("Foo");
  95. var bar = control.FindControl<ContentControl>("Bar");
  96. Assert.Contains(foo, panel.Children);
  97. Assert.Contains(bar, panel.Children);
  98. }
  99. [Fact]
  100. public void ControlTemplate_With_Nested_Child_Is_Operational()
  101. {
  102. var xaml = @"
  103. <ControlTemplate xmlns='https://github.com/avaloniaui'>
  104. <ContentControl Name='parent'>
  105. <ContentControl Name='child' />
  106. </ContentControl>
  107. </ControlTemplate>
  108. ";
  109. var template = AvaloniaXamlLoader.Parse<ControlTemplate>(xaml);
  110. var parent = (ContentControl)template.Build(new ContentControl());
  111. Assert.Equal("parent", parent.Name);
  112. var child = parent.Content as ContentControl;
  113. Assert.NotNull(child);
  114. Assert.Equal("child", child.Name);
  115. }
  116. [Fact]
  117. public void ControlTemplate_With_Panel_Children_Are_Added()
  118. {
  119. var xaml = @"
  120. <ControlTemplate xmlns='https://github.com/avaloniaui'>
  121. <Panel Name='panel'>
  122. <ContentControl Name='Foo' />
  123. <ContentControl Name='Bar' />
  124. </Panel>
  125. </ControlTemplate>
  126. ";
  127. var template = AvaloniaXamlLoader.Parse<ControlTemplate>(xaml);
  128. var panel = (Panel)template.Build(new ContentControl());
  129. Assert.Equal(2, panel.Children.Count);
  130. var foo = panel.Children[0];
  131. var bar = panel.Children[1];
  132. Assert.Equal("Foo", foo.Name);
  133. Assert.Equal("Bar", bar.Name);
  134. }
  135. [Fact]
  136. public void Named_x_Control_Is_Added_To_NameScope_Simple()
  137. {
  138. var xaml = @"
  139. <UserControl xmlns='https://github.com/avaloniaui'
  140. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  141. <Button x:Name='button'>Foo</Button>
  142. </UserControl>";
  143. var control = AvaloniaXamlLoader.Parse<UserControl>(xaml);
  144. var button = control.FindControl<Button>("button");
  145. Assert.Equal("Foo", button.Content);
  146. }
  147. [Fact]
  148. public void Standart_TypeConverter_Is_Used()
  149. {
  150. var xaml = @"<UserControl xmlns='https://github.com/avaloniaui' Width='200.5' />";
  151. var control = AvaloniaXamlLoader.Parse<UserControl>(xaml);
  152. Assert.Equal(200.5, control.Width);
  153. }
  154. [Fact]
  155. public void Avalonia_TypeConverter_Is_Used()
  156. {
  157. var xaml = @"<UserControl xmlns='https://github.com/avaloniaui' Background='White' />";
  158. var control = AvaloniaXamlLoader.Parse<UserControl>(xaml);
  159. var bk = control.Background;
  160. Assert.IsType<SolidColorBrush>(bk);
  161. Assert.Equal(Colors.White, (bk as SolidColorBrush).Color);
  162. }
  163. [Fact]
  164. public void Simple_Style_Is_Parsed()
  165. {
  166. var xaml = @"
  167. <Styles xmlns='https://github.com/avaloniaui'
  168. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  169. <Style Selector='TextBlock'>
  170. <Setter Property='Background' Value='White'/>
  171. <Setter Property='Width' Value='100'/>
  172. </Style>
  173. </Styles>";
  174. var styles = AvaloniaXamlLoader.Parse<Styles>(xaml);
  175. Assert.Equal(1, styles.Count);
  176. var style = (Style)styles[0];
  177. var setters = style.Setters.Cast<Setter>().ToArray();
  178. Assert.Equal(2, setters.Length);
  179. Assert.Equal(TextBlock.BackgroundProperty, setters[0].Property);
  180. Assert.Equal(Brushes.White, setters[0].Value);
  181. Assert.Equal(TextBlock.WidthProperty, setters[1].Property);
  182. Assert.Equal(100.0, setters[1].Value);
  183. }
  184. [Fact]
  185. public void Style_Setter_With_AttachedProperty_Is_Parsed()
  186. {
  187. var xaml = @"
  188. <Styles xmlns='https://github.com/avaloniaui'
  189. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  190. <Style Selector='ContentControl'>
  191. <Setter Property='TextBlock.FontSize' Value='21'/>
  192. </Style>
  193. </Styles>";
  194. var styles = AvaloniaXamlLoader.Parse<Styles>(xaml);
  195. Assert.Equal(1, styles.Count);
  196. var style = (Style)styles[0];
  197. var setters = style.Setters.Cast<Setter>().ToArray();
  198. Assert.Equal(1, setters.Length);
  199. Assert.Equal(TextBlock.FontSizeProperty, setters[0].Property);
  200. Assert.Equal(21.0, setters[0].Value);
  201. }
  202. [Fact]
  203. public void Complex_Style_Is_Parsed()
  204. {
  205. using (UnitTestApplication.Start(TestServices.StyledWindow))
  206. {
  207. var xaml = @"
  208. <Styles xmlns='https://github.com/avaloniaui'>
  209. <Style Selector='CheckBox'>
  210. <Setter Property='BorderBrush' Value='{StyleResource ThemeBorderMidBrush}'/>
  211. <Setter Property='BorderThickness' Value='{StyleResource ThemeBorderThickness}'/>
  212. <Setter Property='Template'>
  213. <ControlTemplate>
  214. <Grid ColumnDefinitions='Auto,*'>
  215. <Border Name='border'
  216. BorderBrush='{TemplateBinding BorderBrush}'
  217. BorderThickness='{TemplateBinding BorderThickness}'
  218. Width='18'
  219. Height='18'
  220. VerticalAlignment='Center'>
  221. <Path Name='checkMark'
  222. Fill='{StyleResource HighlightBrush}'
  223. Width='11'
  224. Height='10'
  225. Stretch='Uniform'
  226. HorizontalAlignment='Center'
  227. VerticalAlignment='Center'
  228. 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'/>
  229. </Border>
  230. <ContentPresenter Name='PART_ContentPresenter'
  231. Content='{TemplateBinding Content}'
  232. ContentTemplate='{TemplateBinding ContentTemplate}'
  233. Margin='4,0,0,0'
  234. VerticalAlignment='Center'
  235. Grid.Column='1'/>
  236. </Grid>
  237. </ControlTemplate>
  238. </Setter>
  239. </Style>
  240. </Styles>
  241. ";
  242. var styles = AvaloniaXamlLoader.Parse<Styles>(xaml);
  243. Assert.Equal(1, styles.Count);
  244. var style = (Style)styles[0];
  245. var setters = style.Setters.Cast<Setter>().ToArray();
  246. Assert.Equal(3, setters.Length);
  247. Assert.Equal(CheckBox.BorderBrushProperty, setters[0].Property);
  248. Assert.Equal(CheckBox.BorderThicknessProperty, setters[1].Property);
  249. Assert.Equal(CheckBox.TemplateProperty, setters[2].Property);
  250. Assert.IsType<StyleResourceBinding>(setters[0].Value);
  251. Assert.IsType<StyleResourceBinding>(setters[1].Value);
  252. Assert.IsType<ControlTemplate>(setters[2].Value);
  253. }
  254. }
  255. [Fact]
  256. public void Style_Resources_Are_Build()
  257. {
  258. var xaml = @"
  259. <Style xmlns='https://github.com/avaloniaui'
  260. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  261. xmlns:sys='clr-namespace:System;assembly=mscorlib'>
  262. <Style.Resources>
  263. <SolidColorBrush x:Key='Brush'>White</SolidColorBrush>
  264. <sys:Double x:Key='Double'>10</sys:Double>
  265. </Style.Resources>
  266. </Style>";
  267. var style = AvaloniaXamlLoader.Parse<Style>(xaml);
  268. Assert.True(style.Resources.Count > 0);
  269. var brush = style.FindResource("Brush") as SolidColorBrush;
  270. Assert.NotNull(brush);
  271. Assert.Equal(Colors.White, brush.Color);
  272. var d = (double)style.FindResource("Double");
  273. Assert.Equal(10.0, d);
  274. }
  275. [Fact]
  276. public void StyleInclude_Is_Build()
  277. {
  278. using (UnitTestApplication.Start(TestServices.StyledWindow))
  279. {
  280. var xaml = @"
  281. <Styles xmlns='https://github.com/avaloniaui'
  282. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  283. <StyleInclude Source='resm:Avalonia.Themes.Default.ContextMenu.xaml?assembly=Avalonia.Themes.Default'/>
  284. </Styles>";
  285. var styles = AvaloniaXamlLoader.Parse<Styles>(xaml);
  286. Assert.True(styles.Count == 1);
  287. var styleInclude = styles.First() as StyleInclude;
  288. Assert.NotNull(styleInclude);
  289. var style = styleInclude.Loaded;
  290. Assert.NotNull(style);
  291. }
  292. }
  293. [Fact]
  294. public void Simple_Xaml_Binding_Is_Operational()
  295. {
  296. using (UnitTestApplication.Start(TestServices.MockPlatformWrapper
  297. .With(windowingPlatform: new MockWindowingPlatform())))
  298. {
  299. var xaml =
  300. @"<Window xmlns='https://github.com/avaloniaui' Content='{Binding}'/>";
  301. var target = AvaloniaXamlLoader.Parse<ContentControl>(xaml);
  302. Assert.Null(target.Content);
  303. target.DataContext = "Foo";
  304. Assert.Equal("Foo", target.Content);
  305. }
  306. }
  307. [Fact]
  308. public void Xaml_Binding_Is_Delayed()
  309. {
  310. using (UnitTestApplication.Start(TestServices.MockPlatformWrapper
  311. .With(windowingPlatform: new MockWindowingPlatform())))
  312. {
  313. var xaml =
  314. @"<ContentControl xmlns='https://github.com/avaloniaui' Content='{Binding}'/>";
  315. var target = AvaloniaXamlLoader.Parse<ContentControl>(xaml);
  316. Assert.Null(target.Content);
  317. target.DataContext = "Foo";
  318. Assert.Null(target.Content);
  319. DelayedBinding.ApplyBindings(target);
  320. Assert.Equal("Foo", target.Content);
  321. }
  322. }
  323. [Fact]
  324. public void Double_Xaml_Binding_Is_Operational()
  325. {
  326. using (UnitTestApplication.Start(TestServices.MockPlatformWrapper
  327. .With(windowingPlatform: new MockWindowingPlatform())))
  328. {
  329. var xaml =
  330. @"<Window xmlns='https://github.com/avaloniaui' Width='{Binding}'/>";
  331. var target = AvaloniaXamlLoader.Parse<ContentControl>(xaml);
  332. Assert.Null(target.Content);
  333. target.DataContext = 55.0;
  334. Assert.Equal(55.0, target.Width);
  335. }
  336. }
  337. [Fact]
  338. public void Collection_Xaml_Binding_Is_Operational()
  339. {
  340. using (UnitTestApplication.Start(TestServices.MockPlatformWrapper
  341. .With(windowingPlatform: new MockWindowingPlatform())))
  342. {
  343. var xaml = @"
  344. <Window xmlns='https://github.com/avaloniaui'>
  345. <ItemsControl Name='itemsControl' Items='{Binding}'>
  346. </ItemsControl>
  347. </Window>
  348. ";
  349. var target = AvaloniaXamlLoader.Parse<Window>(xaml);
  350. Assert.NotNull(target.Content);
  351. var itemsControl = target.FindControl<ItemsControl>("itemsControl");
  352. var items = new string[] { "Foo", "Bar" };
  353. target.DataContext = items;
  354. Assert.Equal(items, itemsControl.Items);
  355. }
  356. }
  357. [Fact]
  358. public void Multi_Xaml_Binding_Is_Parsed()
  359. {
  360. var xaml =
  361. @"<MultiBinding xmlns='https://github.com/avaloniaui'
  362. Converter='{Static BoolConverters.And}'>
  363. <Binding Path='Foo' />
  364. <Binding Path='Bar' />
  365. </MultiBinding>";
  366. var target = AvaloniaXamlLoader.Parse<MultiBinding>(xaml);
  367. Assert.Equal(2, target.Bindings.Count);
  368. Assert.Equal(BoolConverters.And, target.Converter);
  369. var bindings = target.Bindings.Cast<Binding>().ToArray();
  370. Assert.Equal("Foo", bindings[0].Path);
  371. Assert.Equal("Bar", bindings[1].Path);
  372. }
  373. #if OMNIXAML
  374. [Fact(Skip ="OmniXaml doesn't support set property with base class prefix ...")]
  375. #else
  376. [Fact]
  377. #endif
  378. public void Control_Template_Is_Operational()
  379. {
  380. using (UnitTestApplication.Start(TestServices.MockPlatformWrapper
  381. .With(windowingPlatform: new MockWindowingPlatform())))
  382. {
  383. var xaml = @"
  384. <Window xmlns='https://github.com/avaloniaui'
  385. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  386. <ContentControl.Template>
  387. <ControlTemplate>
  388. <ContentPresenter Name='PART_ContentPresenter'
  389. Content='{TemplateBinding Content}'/>
  390. </ControlTemplate>
  391. </ContentControl.Template>
  392. </Window>";
  393. var target = AvaloniaXamlLoader.Parse<ContentControl>(xaml);
  394. Assert.NotNull(target.Template);
  395. Assert.Null(target.Presenter);
  396. target.ApplyTemplate();
  397. Assert.NotNull(target.Presenter);
  398. target.Content = "Foo";
  399. Assert.Equal("Foo", target.Presenter.Content);
  400. }
  401. }
  402. [Fact]
  403. public void Style_ControlTemplate_Is_Build()
  404. {
  405. var xaml = @"
  406. <Style xmlns='https://github.com/avaloniaui' Selector='ContentControl'>
  407. <Setter Property='Template'>
  408. <ControlTemplate>
  409. <ContentPresenter Name='PART_ContentPresenter'
  410. Content='{TemplateBinding Content}'
  411. ContentTemplate='{TemplateBinding ContentTemplate}' />
  412. </ControlTemplate>
  413. </Setter>
  414. </Style> ";
  415. var style = AvaloniaXamlLoader.Parse<Style>(xaml);
  416. Assert.Equal(1, style.Setters.Count());
  417. var setter = (Setter)style.Setters.First();
  418. Assert.Equal(ContentControl.TemplateProperty, setter.Property);
  419. Assert.IsType<ControlTemplate>(setter.Value);
  420. var template = (ControlTemplate)setter.Value;
  421. var control = new ContentControl();
  422. var result = (ContentPresenter)template.Build(control);
  423. Assert.NotNull(result);
  424. }
  425. [Fact]
  426. public void Named_Control_Is_Added_To_NameScope()
  427. {
  428. using (UnitTestApplication.Start(TestServices.StyledWindow))
  429. {
  430. var xaml = @"
  431. <Window xmlns='https://github.com/avaloniaui'
  432. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  433. <Button Name='button'>Foo</Button>
  434. </Window>";
  435. var window = AvaloniaXamlLoader.Parse<Window>(xaml);
  436. var button = window.FindControl<Button>("button");
  437. Assert.Equal("Foo", button.Content);
  438. }
  439. }
  440. [Fact]
  441. public void Control_Is_Added_To_Parent_Before_Properties_Are_Set()
  442. {
  443. using (UnitTestApplication.Start(TestServices.StyledWindow))
  444. {
  445. var xaml = @"
  446. <Window xmlns='https://github.com/avaloniaui'
  447. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  448. xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'>
  449. <local:InitializationOrderTracker Width='100'/>
  450. </Window>";
  451. var window = AvaloniaXamlLoader.Parse<Window>(xaml);
  452. var tracker = (InitializationOrderTracker)window.Content;
  453. var attached = tracker.Order.IndexOf("AttachedToLogicalTree");
  454. var widthChanged = tracker.Order.IndexOf("Property Width Changed");
  455. Assert.NotEqual(-1, attached);
  456. Assert.NotEqual(-1, widthChanged);
  457. Assert.True(attached < widthChanged);
  458. }
  459. }
  460. }
  461. }