DynamicResourceExtensionTests.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  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 System.Linq;
  5. using Avalonia.Controls;
  6. using Avalonia.Controls.Presenters;
  7. using Avalonia.Controls.Templates;
  8. using Avalonia.Markup.Xaml.Data;
  9. using Avalonia.Media;
  10. using Avalonia.Styling;
  11. using Avalonia.UnitTests;
  12. using Avalonia.VisualTree;
  13. using Xunit;
  14. namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
  15. {
  16. public class DynamicResourceExtensionTests
  17. {
  18. [Fact]
  19. public void DynamicResource_Can_Be_Assigned_To_Property()
  20. {
  21. var xaml = @"
  22. <UserControl xmlns='https://github.com/avaloniaui'
  23. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  24. <UserControl.Resources>
  25. <SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush>
  26. </UserControl.Resources>
  27. <Border Name='border' Background='{DynamicResource brush}'/>
  28. </UserControl>";
  29. var loader = new AvaloniaXamlLoader();
  30. var userControl = (UserControl)loader.Load(xaml);
  31. var border = userControl.FindControl<Border>("border");
  32. DelayedBinding.ApplyBindings(border);
  33. var brush = (SolidColorBrush)border.Background;
  34. Assert.Equal(0xff506070, brush.Color.ToUint32());
  35. }
  36. [Fact]
  37. public void DynamicResource_Can_Be_Assigned_To_Attached_Property()
  38. {
  39. var xaml = @"
  40. <UserControl xmlns='https://github.com/avaloniaui'
  41. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  42. <UserControl.Resources>
  43. <x:Int32 x:Key='col'>5</x:Int32>
  44. </UserControl.Resources>
  45. <Border Name='border' Grid.Column='{DynamicResource col}'/>
  46. </UserControl>";
  47. var loader = new AvaloniaXamlLoader();
  48. var userControl = (UserControl)loader.Load(xaml);
  49. var border = userControl.FindControl<Border>("border");
  50. DelayedBinding.ApplyBindings(border);
  51. Assert.Equal(5, Grid.GetColumn(border));
  52. }
  53. [Fact]
  54. public void DynamicResource_From_Style_Can_Be_Assigned_To_Property()
  55. {
  56. var xaml = @"
  57. <UserControl xmlns='https://github.com/avaloniaui'
  58. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  59. <UserControl.Styles>
  60. <Style>
  61. <Style.Resources>
  62. <SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush>
  63. </Style.Resources>
  64. </Style>
  65. </UserControl.Styles>
  66. <Border Name='border' Background='{DynamicResource brush}'/>
  67. </UserControl>";
  68. var loader = new AvaloniaXamlLoader();
  69. var userControl = (UserControl)loader.Load(xaml);
  70. var border = userControl.FindControl<Border>("border");
  71. DelayedBinding.ApplyBindings(border);
  72. var brush = (SolidColorBrush)border.Background;
  73. Assert.Equal(0xff506070, brush.Color.ToUint32());
  74. }
  75. [Fact]
  76. public void DynamicResource_From_Application_Can_Be_Assigned_To_Property_In_Window()
  77. {
  78. using (StyledWindow())
  79. {
  80. Application.Current.Resources.Add("brush", new SolidColorBrush(0xff506070));
  81. var xaml = @"
  82. <Window xmlns='https://github.com/avaloniaui'
  83. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  84. <Border Name='border' Background='{DynamicResource brush}'/>
  85. </Window>";
  86. var loader = new AvaloniaXamlLoader();
  87. var window = (Window)loader.Load(xaml);
  88. var border = window.FindControl<Border>("border");
  89. var brush = (SolidColorBrush)border.Background;
  90. Assert.Equal(0xff506070, brush.Color.ToUint32());
  91. }
  92. }
  93. [Fact]
  94. public void DynamicResource_From_Application_Can_Be_Assigned_To_Property_In_UserControl()
  95. {
  96. using (UnitTestApplication.Start(TestServices.StyledWindow))
  97. {
  98. Application.Current.Resources.Add("brush", new SolidColorBrush(0xff506070));
  99. var xaml = @"
  100. <UserControl xmlns='https://github.com/avaloniaui'
  101. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  102. <Border Name='border' Background='{DynamicResource brush}'/>
  103. </UserControl>";
  104. var loader = new AvaloniaXamlLoader();
  105. var userControl = (UserControl)loader.Load(xaml);
  106. var border = userControl.FindControl<Border>("border");
  107. // We don't actually know where the global styles are until we attach the control
  108. // to a window, as Window has StylingParent set to Application.
  109. var window = new Window { Content = userControl };
  110. window.Show();
  111. var brush = (SolidColorBrush)border.Background;
  112. Assert.Equal(0xff506070, brush.Color.ToUint32());
  113. }
  114. }
  115. [Fact]
  116. public void DynamicResource_Can_Be_Assigned_To_Setter()
  117. {
  118. using (StyledWindow())
  119. {
  120. var xaml = @"
  121. <Window xmlns='https://github.com/avaloniaui'
  122. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  123. <Window.Resources>
  124. <SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush>
  125. </Window.Resources>
  126. <Window.Styles>
  127. <Style Selector='Button'>
  128. <Setter Property='Background' Value='{DynamicResource brush}'/>
  129. </Style>
  130. </Window.Styles>
  131. <Button Name='button'/>
  132. </Window>";
  133. var loader = new AvaloniaXamlLoader();
  134. var window = (Window)loader.Load(xaml);
  135. var button = window.FindControl<Button>("button");
  136. var brush = (SolidColorBrush)button.Background;
  137. Assert.Equal(0xff506070, brush.Color.ToUint32());
  138. }
  139. }
  140. [Fact]
  141. public void DynamicResource_From_Style_Can_Be_Assigned_To_Setter()
  142. {
  143. using (StyledWindow())
  144. {
  145. var xaml = @"
  146. <Window xmlns='https://github.com/avaloniaui'
  147. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  148. <Window.Styles>
  149. <Style>
  150. <Style.Resources>
  151. <SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush>
  152. </Style.Resources>
  153. </Style>
  154. <Style Selector='Button'>
  155. <Setter Property='Background' Value='{DynamicResource brush}'/>
  156. </Style>
  157. </Window.Styles>
  158. <Button Name='button'/>
  159. </Window>";
  160. var loader = new AvaloniaXamlLoader();
  161. var window = (Window)loader.Load(xaml);
  162. var button = window.FindControl<Button>("button");
  163. var brush = (SolidColorBrush)button.Background;
  164. Assert.Equal(0xff506070, brush.Color.ToUint32());
  165. }
  166. }
  167. [Fact]
  168. public void DynamicResource_Can_Be_Assigned_To_Setter_In_Styles_File()
  169. {
  170. var styleXaml = @"
  171. <Styles xmlns='https://github.com/avaloniaui'
  172. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  173. <Styles.Resources>
  174. <SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush>
  175. </Styles.Resources>
  176. <Style Selector='Border'>
  177. <Setter Property='Background' Value='{DynamicResource brush}'/>
  178. </Style>
  179. </Styles>";
  180. using (StyledWindow(assets: ("test:style.xaml", styleXaml)))
  181. {
  182. var xaml = @"
  183. <Window xmlns='https://github.com/avaloniaui'
  184. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  185. <Window.Styles>
  186. <StyleInclude Source='test:style.xaml'/>
  187. </Window.Styles>
  188. <Border Name='border'/>
  189. </Window>";
  190. var loader = new AvaloniaXamlLoader();
  191. var window = (Window)loader.Load(xaml);
  192. var border = window.FindControl<Border>("border");
  193. var brush = (SolidColorBrush)border.Background;
  194. Assert.Equal(0xff506070, brush.Color.ToUint32());
  195. }
  196. }
  197. [Fact]
  198. public void DynamicResource_Can_Be_Assigned_To_Property_In_ControlTemplate_In_Styles_File()
  199. {
  200. var styleXaml = @"
  201. <Styles xmlns='https://github.com/avaloniaui'
  202. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  203. <Styles.Resources>
  204. <SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush>
  205. </Styles.Resources>
  206. <Style Selector='Button'>
  207. <Setter Property='Template'>
  208. <ControlTemplate>
  209. <Border Name='border' Background='{DynamicResource brush}'/>
  210. </ControlTemplate>
  211. </Setter>
  212. </Style>
  213. </Styles>";
  214. using (StyledWindow(assets: ("test:style.xaml", styleXaml)))
  215. {
  216. var xaml = @"
  217. <Window xmlns='https://github.com/avaloniaui'
  218. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  219. <Window.Styles>
  220. <StyleInclude Source='test:style.xaml'/>
  221. </Window.Styles>
  222. <Button Name='button'/>
  223. </Window>";
  224. var loader = new AvaloniaXamlLoader();
  225. var window = (Window)loader.Load(xaml);
  226. var button = window.FindControl<Button>("button");
  227. window.Show();
  228. var border = (Border)button.GetVisualChildren().Single();
  229. var brush = (SolidColorBrush)border.Background;
  230. Assert.Equal(0xff506070, brush.Color.ToUint32());
  231. }
  232. }
  233. [Fact]
  234. public void DynamicResource_Can_Be_Assigned_To_Resource_Property()
  235. {
  236. var xaml = @"
  237. <UserControl xmlns='https://github.com/avaloniaui'
  238. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  239. <UserControl.Resources>
  240. <Color x:Key='color'>#ff506070</Color>
  241. <SolidColorBrush x:Key='brush' Color='{DynamicResource color}'/>
  242. </UserControl.Resources>
  243. <Border Name='border' Background='{DynamicResource brush}'/>
  244. </UserControl>";
  245. var loader = new AvaloniaXamlLoader();
  246. var userControl = (UserControl)loader.Load(xaml);
  247. var border = userControl.FindControl<Border>("border");
  248. DelayedBinding.ApplyBindings(border);
  249. var brush = (SolidColorBrush)border.Background;
  250. Assert.Equal(0xff506070, brush.Color.ToUint32());
  251. }
  252. [Fact]
  253. public void DynamicResource_Tracks_Added_Resource()
  254. {
  255. var xaml = @"
  256. <UserControl xmlns='https://github.com/avaloniaui'
  257. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  258. <Border Name='border' Background='{DynamicResource brush}'/>
  259. </UserControl>";
  260. var loader = new AvaloniaXamlLoader();
  261. var userControl = (UserControl)loader.Load(xaml);
  262. var border = userControl.FindControl<Border>("border");
  263. DelayedBinding.ApplyBindings(border);
  264. Assert.Null(border.Background);
  265. userControl.Resources.Add("brush", new SolidColorBrush(0xff506070));
  266. var brush = (SolidColorBrush)border.Background;
  267. Assert.NotNull(brush);
  268. Assert.Equal(0xff506070, brush.Color.ToUint32());
  269. }
  270. [Fact]
  271. public void DynamicResource_Tracks_Added_Style_Resource()
  272. {
  273. var xaml = @"
  274. <UserControl xmlns='https://github.com/avaloniaui'
  275. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  276. <Border Name='border' Background='{DynamicResource brush}'/>
  277. </UserControl>";
  278. var loader = new AvaloniaXamlLoader();
  279. var userControl = (UserControl)loader.Load(xaml);
  280. var border = userControl.FindControl<Border>("border");
  281. DelayedBinding.ApplyBindings(border);
  282. Assert.Null(border.Background);
  283. userControl.Styles.Resources.Add("brush", new SolidColorBrush(0xff506070));
  284. var brush = (SolidColorBrush)border.Background;
  285. Assert.NotNull(brush);
  286. Assert.Equal(0xff506070, brush.Color.ToUint32());
  287. }
  288. [Fact]
  289. public void DynamicResource_Tracks_Added_Nested_Style_Resource()
  290. {
  291. var xaml = @"
  292. <UserControl xmlns='https://github.com/avaloniaui'
  293. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  294. <UserControl.Styles>
  295. <Style>
  296. </Style>
  297. </UserControl.Styles>
  298. <Border Name='border' Background='{DynamicResource brush}'/>
  299. </UserControl>";
  300. var loader = new AvaloniaXamlLoader();
  301. var userControl = (UserControl)loader.Load(xaml);
  302. var border = userControl.FindControl<Border>("border");
  303. DelayedBinding.ApplyBindings(border);
  304. Assert.Null(border.Background);
  305. ((Style)userControl.Styles[0]).Resources.Add("brush", new SolidColorBrush(0xff506070));
  306. var brush = (SolidColorBrush)border.Background;
  307. Assert.NotNull(brush);
  308. Assert.Equal(0xff506070, brush.Color.ToUint32());
  309. }
  310. [Fact]
  311. public void DynamicResource_Can_Be_Found_Across_Xaml_Style_Files()
  312. {
  313. var style1Xaml = @"
  314. <Style xmlns='https://github.com/avaloniaui'
  315. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  316. <Style.Resources>
  317. <Color x:Key='Red'>Red</Color>
  318. </Style.Resources>
  319. </Style>";
  320. var style2Xaml = @"
  321. <Style xmlns='https://github.com/avaloniaui'
  322. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  323. <Style.Resources>
  324. <SolidColorBrush x:Key='RedBrush' Color='{DynamicResource Red}'/>
  325. </Style.Resources>
  326. </Style>";
  327. using (StyledWindow(
  328. ("test:style1.xaml", style1Xaml),
  329. ("test:style2.xaml", style2Xaml)))
  330. {
  331. var xaml = @"
  332. <Window xmlns='https://github.com/avaloniaui'
  333. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  334. <Window.Styles>
  335. <StyleInclude Source='test:style1.xaml'/>
  336. <StyleInclude Source='test:style2.xaml'/>
  337. </Window.Styles>
  338. <Border Name='border' Background='{DynamicResource RedBrush}'/>
  339. </Window>";
  340. var loader = new AvaloniaXamlLoader();
  341. var window = (Window)loader.Load(xaml);
  342. var border = window.FindControl<Border>("border");
  343. var borderBrush = (ISolidColorBrush)border.Background;
  344. Assert.NotNull(borderBrush);
  345. Assert.Equal(0xffff0000, borderBrush.Color.ToUint32());
  346. }
  347. }
  348. [Fact]
  349. public void Control_Property_Is_Updated_When_Parent_Is_Changed()
  350. {
  351. var xaml = @"
  352. <UserControl xmlns='https://github.com/avaloniaui'
  353. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  354. <UserControl.Resources>
  355. <SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush>
  356. </UserControl.Resources>
  357. <Border Name='border' Background='{DynamicResource brush}'/>
  358. </UserControl>";
  359. var loader = new AvaloniaXamlLoader();
  360. var userControl = (UserControl)loader.Load(xaml);
  361. var border = userControl.FindControl<Border>("border");
  362. DelayedBinding.ApplyBindings(border);
  363. var brush = (SolidColorBrush)border.Background;
  364. Assert.Equal(0xff506070, brush.Color.ToUint32());
  365. userControl.Content = null;
  366. Assert.Null(border.Background);
  367. userControl.Content = border;
  368. brush = (SolidColorBrush)border.Background;
  369. Assert.Equal(0xff506070, brush.Color.ToUint32());
  370. }
  371. private IDisposable StyledWindow(params (string, string)[] assets)
  372. {
  373. var services = TestServices.StyledWindow.With(
  374. assetLoader: new MockAssetLoader(assets),
  375. theme: () => new Styles
  376. {
  377. WindowStyle(),
  378. });
  379. return UnitTestApplication.Start(services);
  380. }
  381. private Style WindowStyle()
  382. {
  383. return new Style(x => x.OfType<Window>())
  384. {
  385. Setters =
  386. {
  387. new Setter(
  388. Window.TemplateProperty,
  389. new FuncControlTemplate<Window>(x =>
  390. new ContentPresenter
  391. {
  392. Name = "PART_ContentPresenter",
  393. [!ContentPresenter.ContentProperty] = x[!Window.ContentProperty],
  394. }))
  395. }
  396. };
  397. }
  398. }
  399. }