DynamicResourceExtensionTests.cs 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Avalonia.Controls;
  5. using Avalonia.Controls.Presenters;
  6. using Avalonia.Controls.Templates;
  7. using Avalonia.Markup.Data;
  8. using Avalonia.Media;
  9. using Avalonia.Styling;
  10. using Avalonia.UnitTests;
  11. using Avalonia.VisualTree;
  12. using Xunit;
  13. namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
  14. {
  15. public class DynamicResourceExtensionTests : XamlTestBase
  16. {
  17. [Fact]
  18. public void DynamicResource_Can_Be_Assigned_To_Property()
  19. {
  20. var xaml = @"
  21. <UserControl xmlns='https://github.com/avaloniaui'
  22. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  23. <UserControl.Resources>
  24. <SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush>
  25. </UserControl.Resources>
  26. <Border Name='border' Background='{DynamicResource brush}'/>
  27. </UserControl>";
  28. var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
  29. var border = userControl.FindControl<Border>("border");
  30. DelayedBinding.ApplyBindings(border);
  31. var brush = (ISolidColorBrush)border.Background;
  32. Assert.Equal(0xff506070, brush.Color.ToUInt32());
  33. }
  34. [Fact]
  35. public void DynamicResource_Can_Be_Assigned_To_Attached_Property()
  36. {
  37. var xaml = @"
  38. <UserControl xmlns='https://github.com/avaloniaui'
  39. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  40. <UserControl.Resources>
  41. <x:Int32 x:Key='col'>5</x:Int32>
  42. </UserControl.Resources>
  43. <Border Name='border' Grid.Column='{DynamicResource col}'/>
  44. </UserControl>";
  45. var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
  46. var border = userControl.FindControl<Border>("border");
  47. DelayedBinding.ApplyBindings(border);
  48. Assert.Equal(5, Grid.GetColumn(border));
  49. }
  50. [Fact]
  51. public void DynamicResource_From_Style_Can_Be_Assigned_To_Property()
  52. {
  53. var xaml = @"
  54. <UserControl xmlns='https://github.com/avaloniaui'
  55. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  56. <UserControl.Styles>
  57. <Style>
  58. <Style.Resources>
  59. <SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush>
  60. </Style.Resources>
  61. </Style>
  62. </UserControl.Styles>
  63. <Border Name='border' Background='{DynamicResource brush}'/>
  64. </UserControl>";
  65. var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
  66. var border = userControl.FindControl<Border>("border");
  67. DelayedBinding.ApplyBindings(border);
  68. var brush = (ISolidColorBrush)border.Background;
  69. Assert.Equal(0xff506070, brush.Color.ToUInt32());
  70. }
  71. [Fact]
  72. public void DynamicResource_From_MergedDictionary_Can_Be_Assigned_To_Property()
  73. {
  74. var xaml = @"
  75. <UserControl xmlns='https://github.com/avaloniaui'
  76. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  77. <UserControl.Resources>
  78. <ResourceDictionary>
  79. <ResourceDictionary.MergedDictionaries>
  80. <ResourceDictionary>
  81. <SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush>
  82. </ResourceDictionary>
  83. </ResourceDictionary.MergedDictionaries>
  84. </ResourceDictionary>
  85. </UserControl.Resources>
  86. <Border Name='border' Background='{DynamicResource brush}'/>
  87. </UserControl>";
  88. var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
  89. var border = userControl.FindControl<Border>("border");
  90. DelayedBinding.ApplyBindings(border);
  91. var brush = (ISolidColorBrush)border.Background;
  92. Assert.Equal(0xff506070, brush.Color.ToUInt32());
  93. }
  94. [Fact]
  95. public void DynamicResource_From_MergedDictionary_In_Style_Can_Be_Assigned_To_Property()
  96. {
  97. var xaml = @"
  98. <UserControl xmlns='https://github.com/avaloniaui'
  99. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  100. <UserControl.Styles>
  101. <Style>
  102. <Style.Resources>
  103. <ResourceDictionary>
  104. <ResourceDictionary.MergedDictionaries>
  105. <ResourceDictionary>
  106. <SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush>
  107. </ResourceDictionary>
  108. </ResourceDictionary.MergedDictionaries>
  109. </ResourceDictionary>
  110. </Style.Resources>
  111. </Style>
  112. </UserControl.Styles>
  113. <Border Name='border' Background='{DynamicResource brush}'/>
  114. </UserControl>";
  115. var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
  116. var border = userControl.FindControl<Border>("border");
  117. DelayedBinding.ApplyBindings(border);
  118. var brush = (ISolidColorBrush)border.Background;
  119. Assert.Equal(0xff506070, brush.Color.ToUInt32());
  120. }
  121. [Fact]
  122. public void DynamicResource_From_Application_Can_Be_Assigned_To_Property_In_Window()
  123. {
  124. using (StyledWindow())
  125. {
  126. Application.Current.Resources.Add("brush", new SolidColorBrush(0xff506070));
  127. var xaml = @"
  128. <Window xmlns='https://github.com/avaloniaui'
  129. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  130. <Border Name='border' Background='{DynamicResource brush}'/>
  131. </Window>";
  132. var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
  133. var border = window.FindControl<Border>("border");
  134. var brush = (SolidColorBrush)border.Background;
  135. Assert.Equal(0xff506070, brush.Color.ToUInt32());
  136. }
  137. }
  138. [Fact]
  139. public void DynamicResource_From_Application_Can_Be_Assigned_To_Property_In_UserControl()
  140. {
  141. using (UnitTestApplication.Start(TestServices.StyledWindow))
  142. {
  143. Application.Current.Resources.Add("brush", new SolidColorBrush(0xff506070));
  144. var xaml = @"
  145. <UserControl xmlns='https://github.com/avaloniaui'
  146. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  147. <Border Name='border' Background='{DynamicResource brush}'/>
  148. </UserControl>";
  149. var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
  150. var border = userControl.FindControl<Border>("border");
  151. // We don't actually know where the global styles are until we attach the control
  152. // to a window, as Window has StylingParent set to Application.
  153. var window = new Window { Content = userControl };
  154. window.Show();
  155. var brush = (SolidColorBrush)border.Background;
  156. Assert.Equal(0xff506070, brush.Color.ToUInt32());
  157. }
  158. }
  159. [Fact]
  160. public void DynamicResource_Can_Be_Assigned_To_Setter()
  161. {
  162. using (StyledWindow())
  163. {
  164. var xaml = @"
  165. <Window xmlns='https://github.com/avaloniaui'
  166. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  167. <Window.Resources>
  168. <SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush>
  169. </Window.Resources>
  170. <Window.Styles>
  171. <Style Selector='Button'>
  172. <Setter Property='Background' Value='{DynamicResource brush}'/>
  173. </Style>
  174. </Window.Styles>
  175. <Button Name='button'/>
  176. </Window>";
  177. var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
  178. var button = window.FindControl<Button>("button");
  179. var brush = (ISolidColorBrush)button.Background;
  180. Assert.Equal(0xff506070, brush.Color.ToUInt32());
  181. }
  182. }
  183. [Fact]
  184. public void DynamicResource_From_Style_Can_Be_Assigned_To_Setter()
  185. {
  186. using (StyledWindow())
  187. {
  188. var xaml = @"
  189. <Window xmlns='https://github.com/avaloniaui'
  190. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  191. <Window.Styles>
  192. <Style>
  193. <Style.Resources>
  194. <SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush>
  195. </Style.Resources>
  196. </Style>
  197. <Style Selector='Button'>
  198. <Setter Property='Background' Value='{DynamicResource brush}'/>
  199. </Style>
  200. </Window.Styles>
  201. <Button Name='button'/>
  202. </Window>";
  203. var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
  204. var button = window.FindControl<Button>("button");
  205. var brush = (ISolidColorBrush)button.Background;
  206. Assert.Equal(0xff506070, brush.Color.ToUInt32());
  207. }
  208. }
  209. [Fact]
  210. public void DynamicResource_Can_Be_Assigned_To_Setter_In_Styles_File()
  211. {
  212. var documents = new[]
  213. {
  214. new RuntimeXamlLoaderDocument(new Uri("avares://Tests/Style.xaml"), @"
  215. <Styles xmlns='https://github.com/avaloniaui'
  216. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  217. <Styles.Resources>
  218. <SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush>
  219. </Styles.Resources>
  220. <Style Selector='Border'>
  221. <Setter Property='Background' Value='{DynamicResource brush}'/>
  222. </Style>
  223. </Styles>"),
  224. new RuntimeXamlLoaderDocument(@"
  225. <Window xmlns='https://github.com/avaloniaui'
  226. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  227. <Window.Styles>
  228. <StyleInclude Source='avares://Tests/Style.xaml'/>
  229. </Window.Styles>
  230. <Border Name='border'/>
  231. </Window>")
  232. };
  233. using (StyledWindow())
  234. {
  235. var compiled = AvaloniaRuntimeXamlLoader.LoadGroup(documents);
  236. var window = Assert.IsType<Window>(compiled[1]);
  237. var border = window.FindControl<Border>("border");
  238. var brush = (ISolidColorBrush)border.Background;
  239. Assert.Equal(0xff506070, brush.Color.ToUInt32());
  240. }
  241. }
  242. [Fact]
  243. public void DynamicResource_Can_Be_Assigned_To_Property_In_ControlTemplate_In_Styles_File()
  244. {
  245. var documents = new[]
  246. {
  247. new RuntimeXamlLoaderDocument(new Uri("avares://Tests/Style.xaml"), @"
  248. <Styles xmlns='https://github.com/avaloniaui'
  249. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  250. <Styles.Resources>
  251. <SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush>
  252. </Styles.Resources>
  253. <Style Selector='Button'>
  254. <Setter Property='Template'>
  255. <ControlTemplate>
  256. <Border Name='border' Background='{DynamicResource brush}'/>
  257. </ControlTemplate>
  258. </Setter>
  259. </Style>
  260. </Styles>"),
  261. new RuntimeXamlLoaderDocument(@"
  262. <Window xmlns='https://github.com/avaloniaui'
  263. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  264. <Window.Styles>
  265. <StyleInclude Source='avares://Tests/Style.xaml'/>
  266. </Window.Styles>
  267. <Button Name='button'/>
  268. </Window>")
  269. };
  270. using (StyledWindow())
  271. {
  272. var compiled = AvaloniaRuntimeXamlLoader.LoadGroup(documents);
  273. var window = Assert.IsType<Window>(compiled[1]);
  274. var button = window.FindControl<Button>("button");
  275. window.Show();
  276. var border = (Border)button.GetVisualChildren().Single();
  277. var brush = (ISolidColorBrush)border.Background;
  278. Assert.Equal(0xff506070, brush.Color.ToUInt32());
  279. }
  280. }
  281. [Fact]
  282. public void DynamicResource_Can_Be_Assigned_To_Resource_Property()
  283. {
  284. var xaml = @"
  285. <UserControl xmlns='https://github.com/avaloniaui'
  286. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  287. <UserControl.Resources>
  288. <Color x:Key='color'>#ff506070</Color>
  289. <SolidColorBrush x:Key='brush' Color='{DynamicResource color}'/>
  290. </UserControl.Resources>
  291. <Border Name='border' Background='{DynamicResource brush}'/>
  292. </UserControl>";
  293. var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
  294. var border = userControl.FindControl<Border>("border");
  295. DelayedBinding.ApplyBindings(border);
  296. var brush = (SolidColorBrush)border.Background;
  297. Assert.Equal(0xff506070, brush.Color.ToUInt32());
  298. }
  299. [Fact]
  300. public void DynamicResource_Can_Be_Assigned_To_Resource_Property_In_Application()
  301. {
  302. var xaml = @"
  303. <Application xmlns='https://github.com/avaloniaui'
  304. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  305. <Application.Resources>
  306. <Color x:Key='color'>#ff506070</Color>
  307. <SolidColorBrush x:Key='brush' Color='{DynamicResource color}'/>
  308. </Application.Resources>
  309. </Application>";
  310. var application = (Application)AvaloniaRuntimeXamlLoader.Load(xaml);
  311. var brush = (SolidColorBrush)application.Resources["brush"];
  312. Assert.Equal(0xff506070, brush.Color.ToUInt32());
  313. }
  314. [Fact]
  315. public void DynamicResource_Can_Be_Assigned_To_ItemTemplate_Property()
  316. {
  317. var xaml = @"
  318. <UserControl xmlns='https://github.com/avaloniaui'
  319. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  320. <UserControl.Resources>
  321. <DataTemplate x:Key='PurpleData'>
  322. <TextBlock Text='{Binding Name}' Background='Purple'/>
  323. </DataTemplate>
  324. </UserControl.Resources>
  325. <ListBox Name='listBox' ItemTemplate='{DynamicResource PurpleData}'/>
  326. </UserControl>";
  327. var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
  328. var listBox = userControl.FindControl<ListBox>("listBox");
  329. DelayedBinding.ApplyBindings(listBox);
  330. Assert.NotNull(listBox.ItemTemplate);
  331. }
  332. [Fact]
  333. public void DynamicResource_Tracks_Added_Resource()
  334. {
  335. var xaml = @"
  336. <UserControl xmlns='https://github.com/avaloniaui'
  337. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  338. <Border Name='border' Background='{DynamicResource brush}'/>
  339. </UserControl>";
  340. var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
  341. var border = userControl.FindControl<Border>("border");
  342. DelayedBinding.ApplyBindings(border);
  343. Assert.Null(border.Background);
  344. userControl.Resources.Add("brush", new SolidColorBrush(0xff506070));
  345. var brush = (SolidColorBrush)border.Background;
  346. Assert.NotNull(brush);
  347. Assert.Equal(0xff506070, brush.Color.ToUInt32());
  348. }
  349. [Fact]
  350. public void DynamicResource_Tracks_Added_Style_Resource()
  351. {
  352. var xaml = @"
  353. <UserControl xmlns='https://github.com/avaloniaui'
  354. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  355. <Border Name='border' Background='{DynamicResource brush}'/>
  356. </UserControl>";
  357. var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
  358. var border = userControl.FindControl<Border>("border");
  359. DelayedBinding.ApplyBindings(border);
  360. Assert.Null(border.Background);
  361. userControl.Styles.Resources.Add("brush", new SolidColorBrush(0xff506070));
  362. var brush = (SolidColorBrush)border.Background;
  363. Assert.NotNull(brush);
  364. Assert.Equal(0xff506070, brush.Color.ToUInt32());
  365. }
  366. [Fact]
  367. public void DynamicResource_Tracks_Added_Nested_Style_Resource()
  368. {
  369. var xaml = @"
  370. <UserControl xmlns='https://github.com/avaloniaui'
  371. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  372. <UserControl.Styles>
  373. <Style>
  374. </Style>
  375. </UserControl.Styles>
  376. <Border Name='border' Background='{DynamicResource brush}'/>
  377. </UserControl>";
  378. var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
  379. var border = userControl.FindControl<Border>("border");
  380. DelayedBinding.ApplyBindings(border);
  381. Assert.Null(border.Background);
  382. ((Style)userControl.Styles[0]).Resources.Add("brush", new SolidColorBrush(0xff506070));
  383. var brush = (SolidColorBrush)border.Background;
  384. Assert.NotNull(brush);
  385. Assert.Equal(0xff506070, brush.Color.ToUInt32());
  386. }
  387. [Fact]
  388. public void DynamicResource_Tracks_Added_MergedResource()
  389. {
  390. var xaml = @"
  391. <UserControl xmlns='https://github.com/avaloniaui'
  392. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  393. <UserControl.Resources>
  394. <ResourceDictionary>
  395. <ResourceDictionary.MergedDictionaries>
  396. <ResourceDictionary/>
  397. </ResourceDictionary.MergedDictionaries>
  398. </ResourceDictionary>
  399. </UserControl.Resources>
  400. <Border Name='border' Background='{DynamicResource brush}'/>
  401. </UserControl>";
  402. var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
  403. var border = userControl.FindControl<Border>("border");
  404. DelayedBinding.ApplyBindings(border);
  405. Assert.Null(border.Background);
  406. ((IResourceDictionary)userControl.Resources.MergedDictionaries[0]).Add("brush", new SolidColorBrush(0xff506070));
  407. var brush = (SolidColorBrush)border.Background;
  408. Assert.NotNull(brush);
  409. Assert.Equal(0xff506070, brush.Color.ToUInt32());
  410. }
  411. [Fact]
  412. public void DynamicResource_Tracks_Added_MergedResource_Dictionary()
  413. {
  414. var xaml = @"
  415. <UserControl xmlns='https://github.com/avaloniaui'
  416. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  417. <Border Name='border' Background='{DynamicResource brush}'/>
  418. </UserControl>";
  419. var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
  420. var border = userControl.FindControl<Border>("border");
  421. DelayedBinding.ApplyBindings(border);
  422. Assert.Null(border.Background);
  423. var dictionary = new ResourceDictionary
  424. {
  425. { "brush", new SolidColorBrush(0xff506070) },
  426. };
  427. userControl.Resources.MergedDictionaries.Add(dictionary);
  428. var brush = (SolidColorBrush)border.Background;
  429. Assert.NotNull(brush);
  430. Assert.Equal(0xff506070, brush.Color.ToUInt32());
  431. }
  432. [Fact]
  433. public void DynamicResource_Tracks_Added_Style_MergedResource_Dictionary()
  434. {
  435. var xaml = @"
  436. <UserControl xmlns='https://github.com/avaloniaui'
  437. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  438. <UserControl.Styles>
  439. <Style>
  440. </Style>
  441. </UserControl.Styles>
  442. <Border Name='border' Background='{DynamicResource brush}'/>
  443. </UserControl>";
  444. var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
  445. var border = userControl.FindControl<Border>("border");
  446. DelayedBinding.ApplyBindings(border);
  447. Assert.Null(border.Background);
  448. var dictionary = new ResourceDictionary
  449. {
  450. { "brush", new SolidColorBrush(0xff506070) },
  451. };
  452. ((Style)userControl.Styles[0]).Resources.MergedDictionaries.Add(dictionary);
  453. var brush = (SolidColorBrush)border.Background;
  454. Assert.NotNull(brush);
  455. Assert.Equal(0xff506070, brush.Color.ToUInt32());
  456. }
  457. [Fact]
  458. public void DynamicResource_Can_Be_Found_Across_Xaml_Style_Files()
  459. {
  460. var documents = new[]
  461. {
  462. new RuntimeXamlLoaderDocument(new Uri("avares://Tests/Style1.xaml"), @"
  463. <Style xmlns='https://github.com/avaloniaui'
  464. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  465. <Style.Resources>
  466. <Color x:Key='Red'>Red</Color>
  467. </Style.Resources>
  468. </Style>"),
  469. new RuntimeXamlLoaderDocument(new Uri("avares://Tests/Style2.xaml"), @"
  470. <Style xmlns='https://github.com/avaloniaui'
  471. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  472. <Style.Resources>
  473. <SolidColorBrush x:Key='RedBrush' Color='{DynamicResource Red}'/>
  474. </Style.Resources>
  475. </Style>"),
  476. new RuntimeXamlLoaderDocument(@"
  477. <Window xmlns='https://github.com/avaloniaui'
  478. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  479. <Window.Styles>
  480. <StyleInclude Source='avares://Tests/Style1.xaml'/>
  481. <StyleInclude Source='avares://Tests/Style2.xaml'/>
  482. </Window.Styles>
  483. <Border Name='border' Background='{DynamicResource RedBrush}'/>
  484. </Window>")
  485. };
  486. using (StyledWindow())
  487. {
  488. var compiled = AvaloniaRuntimeXamlLoader.LoadGroup(documents);
  489. var window = Assert.IsType<Window>(compiled[2]);
  490. var border = window.FindControl<Border>("border");
  491. var borderBrush = (ISolidColorBrush)border.Background;
  492. Assert.NotNull(borderBrush);
  493. Assert.Equal(0xffff0000, borderBrush.Color.ToUInt32());
  494. }
  495. }
  496. [Fact]
  497. public void DynamicResource_Can_Be_Found_In_Nested_Style_File()
  498. {
  499. var documents = new[]
  500. {
  501. new RuntimeXamlLoaderDocument(new Uri("avares://Tests/Style1.xaml"), @"
  502. <Styles xmlns='https://github.com/avaloniaui'
  503. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  504. <StyleInclude Source='avares://Tests/Style2.xaml'/>
  505. </Styles>"),
  506. new RuntimeXamlLoaderDocument(new Uri("avares://Tests/Style2.xaml"), @"
  507. <Style xmlns='https://github.com/avaloniaui'
  508. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  509. <Style.Resources>
  510. <Color x:Key='Red'>Red</Color>
  511. <SolidColorBrush x:Key='RedBrush' Color='{DynamicResource Red}'/>
  512. </Style.Resources>
  513. </Style>"),
  514. new RuntimeXamlLoaderDocument(@"
  515. <Window xmlns='https://github.com/avaloniaui'
  516. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  517. <Window.Styles>
  518. <StyleInclude Source='avares://Tests/Style1.xaml'/>
  519. </Window.Styles>
  520. <Border Name='border' Background='{DynamicResource RedBrush}'/>
  521. </Window>")
  522. };
  523. using (StyledWindow())
  524. {
  525. var compiled = AvaloniaRuntimeXamlLoader.LoadGroup(documents);
  526. var window = Assert.IsType<Window>(compiled[2]);
  527. var border = window.FindControl<Border>("border");
  528. var borderBrush = (ISolidColorBrush)border.Background;
  529. Assert.NotNull(borderBrush);
  530. Assert.Equal(0xffff0000, borderBrush.Color.ToUInt32());
  531. }
  532. }
  533. [Fact]
  534. public void Control_Property_Is_Updated_When_Parent_Is_Changed()
  535. {
  536. using (StyledWindow())
  537. {
  538. var xaml = @"
  539. <Window xmlns='https://github.com/avaloniaui'
  540. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  541. <Window.Resources>
  542. <SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush>
  543. </Window.Resources>
  544. <Border Name='border' Background='{DynamicResource brush}'/>
  545. </Window>";
  546. var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
  547. var border = window.FindControl<Border>("border");
  548. DelayedBinding.ApplyBindings(border);
  549. var brush = (ISolidColorBrush)border.Background;
  550. Assert.Equal(0xff506070, brush.Color.ToUInt32());
  551. window.Content = null;
  552. Assert.Null(border.Background);
  553. window.Content = border;
  554. brush = (ISolidColorBrush)border.Background;
  555. Assert.Equal(0xff506070, brush.Color.ToUInt32());
  556. }
  557. }
  558. [Fact]
  559. public void Resource_With_DynamicResource_Is_Updated_When_Added_To_Parent()
  560. {
  561. var xaml = @"
  562. <UserControl xmlns='https://github.com/avaloniaui'
  563. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  564. <UserControl.Resources>
  565. <SolidColorBrush x:Key='brush' Color='{DynamicResource color}'/>
  566. </UserControl.Resources>
  567. <Border Name='border' Background='{DynamicResource brush}'/>
  568. </UserControl>";
  569. var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
  570. var border = userControl.FindControl<Border>("border");
  571. DelayedBinding.ApplyBindings(border);
  572. var brush = (SolidColorBrush)border.Background;
  573. Assert.Equal(0u, brush.Color.ToUInt32());
  574. brush.GetObservable(SolidColorBrush.ColorProperty).Subscribe(_ => { });
  575. using (UnitTestApplication.Start(TestServices.StyledWindow))
  576. {
  577. var window = new Window
  578. {
  579. Resources =
  580. {
  581. { "color", Colors.Red }
  582. },
  583. Content = userControl,
  584. };
  585. window.Show();
  586. Assert.Equal(Colors.Red, brush.Color);
  587. }
  588. }
  589. [Fact]
  590. public void MergedDictionary_Resource_With_DynamicResource_Is_Updated_When_Added_To_Parent()
  591. {
  592. var xaml = @"
  593. <UserControl xmlns='https://github.com/avaloniaui'
  594. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  595. <UserControl.Resources>
  596. <ResourceDictionary>
  597. <ResourceDictionary.MergedDictionaries>
  598. <ResourceDictionary>
  599. <SolidColorBrush x:Key='brush' Color='{DynamicResource color}'/>
  600. </ResourceDictionary>
  601. </ResourceDictionary.MergedDictionaries>
  602. </ResourceDictionary>
  603. </UserControl.Resources>
  604. <Border Name='border' Background='{DynamicResource brush}'/>
  605. </UserControl>";
  606. var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
  607. var border = userControl.FindControl<Border>("border");
  608. DelayedBinding.ApplyBindings(border);
  609. var brush = (SolidColorBrush)border.Background;
  610. Assert.Equal(0u, brush.Color.ToUInt32());
  611. brush.GetObservable(SolidColorBrush.ColorProperty).Subscribe(_ => { });
  612. using (UnitTestApplication.Start(TestServices.StyledWindow))
  613. {
  614. var window = new Window
  615. {
  616. Resources =
  617. {
  618. { "color", Colors.Red }
  619. },
  620. Content = userControl,
  621. };
  622. window.Show();
  623. Assert.Equal(Colors.Red, brush.Color);
  624. }
  625. }
  626. [Fact]
  627. public void Style_Resource_With_DynamicResource_Is_Updated_When_Added_To_Parent()
  628. {
  629. var xaml = @"
  630. <UserControl xmlns='https://github.com/avaloniaui'
  631. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  632. <UserControl.Styles>
  633. <Style>
  634. <Style.Resources>
  635. <SolidColorBrush x:Key='brush' Color='{DynamicResource color}'/>
  636. </Style.Resources>
  637. </Style>
  638. </UserControl.Styles>
  639. <Border Name='border' Background='{DynamicResource brush}'/>
  640. </UserControl>";
  641. var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
  642. var border = userControl.FindControl<Border>("border");
  643. DelayedBinding.ApplyBindings(border);
  644. var brush = (SolidColorBrush)border.Background;
  645. Assert.Equal(0u, brush.Color.ToUInt32());
  646. using (UnitTestApplication.Start(TestServices.StyledWindow))
  647. {
  648. var window = new Window
  649. {
  650. Resources =
  651. {
  652. { "color", Colors.Red }
  653. },
  654. Content = userControl,
  655. };
  656. window.Show();
  657. Assert.Equal(Colors.Red, brush.Color);
  658. }
  659. }
  660. [Fact]
  661. public void Automatically_Converts_Color_To_SolidColorBrush()
  662. {
  663. var xaml = @"
  664. <UserControl xmlns='https://github.com/avaloniaui'
  665. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  666. <UserControl.Resources>
  667. <Color x:Key='color'>#ff506070</Color>
  668. </UserControl.Resources>
  669. <Border Name='border' Background='{DynamicResource color}'/>
  670. </UserControl>";
  671. var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
  672. var border = userControl.FindControl<Border>("border");
  673. var brush = (ISolidColorBrush)border.Background;
  674. Assert.Equal(0xff506070, brush.Color.ToUInt32());
  675. }
  676. [Fact]
  677. public void Resource_In_Non_Matching_Style_Is_Not_Resolved()
  678. {
  679. using var app = StyledWindow();
  680. var xaml = @"
  681. <Window xmlns='https://github.com/avaloniaui'
  682. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  683. xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions'>
  684. <Window.Resources>
  685. <ResourceDictionary>
  686. <ResourceDictionary.MergedDictionaries>
  687. <local:TrackingResourceProvider/>
  688. </ResourceDictionary.MergedDictionaries>
  689. </ResourceDictionary>
  690. </Window.Resources>
  691. <Window.Styles>
  692. <Style Selector='Border.nomatch'>
  693. <Setter Property='Tag' Value='{DynamicResource foo}'/>
  694. </Style>
  695. <Style Selector='Border'>
  696. <Setter Property='Tag' Value='{DynamicResource bar}'/>
  697. </Style>
  698. </Window.Styles>
  699. <Border Name='border'/>
  700. </Window>";
  701. var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
  702. var border = window.FindControl<Border>("border");
  703. Assert.Equal("bar", border.Tag);
  704. var resourceProvider = (TrackingResourceProvider)window.Resources.MergedDictionaries[0];
  705. Assert.Contains("bar", resourceProvider.RequestedResources);
  706. Assert.DoesNotContain("foo", resourceProvider.RequestedResources);
  707. }
  708. [Fact]
  709. public void Resource_In_Non_Active_Style_Is_Not_Resolved()
  710. {
  711. using var app = StyledWindow();
  712. var xaml = @"
  713. <Window xmlns='https://github.com/avaloniaui'
  714. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  715. xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions'>
  716. <Window.Resources>
  717. <ResourceDictionary>
  718. <ResourceDictionary.MergedDictionaries>
  719. <local:TrackingResourceProvider/>
  720. </ResourceDictionary.MergedDictionaries>
  721. </ResourceDictionary>
  722. </Window.Resources>
  723. <Window.Styles>
  724. <Style Selector='Border'>
  725. <Setter Property='Tag' Value='{DynamicResource foo}'/>
  726. </Style>
  727. <Style Selector='Border'>
  728. <Setter Property='Tag' Value='{DynamicResource bar}'/>
  729. </Style>
  730. </Window.Styles>
  731. <Border Name='border'/>
  732. </Window>";
  733. var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
  734. var border = window.FindControl<Border>("border");
  735. Assert.Equal("bar", border.Tag);
  736. var resourceProvider = (TrackingResourceProvider)window.Resources.MergedDictionaries[0];
  737. Assert.Contains("bar", resourceProvider.RequestedResources);
  738. Assert.DoesNotContain("foo", resourceProvider.RequestedResources);
  739. }
  740. [Fact]
  741. public void Can_Detach_Control_With_DynamicResource_ControlTheme_That_Contains_DynamicResource()
  742. {
  743. using var app = UnitTestApplication.Start(TestServices.StyledWindow);
  744. var xaml = $@"
  745. <Window xmlns='https://github.com/avaloniaui'
  746. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  747. RequestedThemeVariant='Light'>
  748. <Window.Resources>
  749. <SolidColorBrush x:Key='Blue'>Blue</SolidColorBrush>
  750. <ControlTheme x:Key='MyTheme' TargetType='Button'>
  751. <Setter Property='Background' Value='{{DynamicResource Blue}}'/>
  752. </ControlTheme>
  753. </Window.Resources>
  754. <Button Theme='{{DynamicResource MyTheme}}'/>
  755. </Window>";
  756. var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
  757. var target = Assert.IsType<Button>(window.Content);
  758. window.Show();
  759. Assert.Equal(Colors.Blue, ((ISolidColorBrush)target.Background).Color);
  760. window.Content = null;
  761. }
  762. [Fact]
  763. public void Handles_Clearing_Resources_With_Dynamic_Theme_In_Dynamic_Template()
  764. {
  765. // Issue #14753
  766. using var app = UnitTestApplication.Start(TestServices.StyledWindow);
  767. var xaml = """
  768. <Window xmlns="https://github.com/avaloniaui"
  769. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  770. <Window.Resources>
  771. <SolidColorBrush x:Key='Blue'>Blue</SolidColorBrush>
  772. <ControlTheme x:Key="MyBorder" TargetType="Border">
  773. <Setter Property="Background" Value="{DynamicResource Blue}"/>
  774. </ControlTheme>
  775. <ControlTheme x:Key="MyButton" TargetType="Button">
  776. <Setter Property="Template">
  777. <ControlTemplate>
  778. <Border Theme="{DynamicResource MyBorder}"/>
  779. </ControlTemplate>
  780. </Setter>
  781. </ControlTheme>
  782. </Window.Resources>
  783. <Button Theme="{DynamicResource MyButton}" Background="{DynamicResource Blue}"/>
  784. </Window>
  785. """;
  786. var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
  787. window.Show();
  788. var button = Assert.IsType<Button>(window.Content);
  789. var border = Assert.IsType<Border>(button.GetVisualChildren().Single());
  790. var background = Assert.IsAssignableFrom<ISolidColorBrush>(border.Background);
  791. Assert.Equal(Colors.Blue, background.Color);
  792. window.Resources.Clear();
  793. }
  794. private IDisposable StyledWindow(params (string, string)[] assets)
  795. {
  796. var services = TestServices.StyledWindow.With(
  797. assetLoader: new MockAssetLoader(assets),
  798. theme: () => new Styles
  799. {
  800. WindowStyle(),
  801. });
  802. return UnitTestApplication.Start(services);
  803. }
  804. private Style WindowStyle()
  805. {
  806. return new Style(x => x.OfType<Window>())
  807. {
  808. Setters =
  809. {
  810. new Setter(
  811. Window.TemplateProperty,
  812. new FuncControlTemplate<Window>((x, scope) =>
  813. new ContentPresenter
  814. {
  815. Name = "PART_ContentPresenter",
  816. [!ContentPresenter.ContentProperty] = x[!Window.ContentProperty],
  817. }.RegisterInNameScope(scope)))
  818. }
  819. };
  820. }
  821. }
  822. public class TrackingResourceProvider : ResourceProvider
  823. {
  824. public override bool HasResources => true;
  825. public List<object> RequestedResources { get; } = new List<object>();
  826. public override bool TryGetResource(object key, ThemeVariant themeVariant, out object value)
  827. {
  828. RequestedResources.Add(key);
  829. value = key;
  830. return true;
  831. }
  832. }
  833. }