Skip to content

Commit 7785828

Browse files
committed
feat(XamlReader): Add support for ThemeResources and MergedDictionaries
1 parent d26dc5b commit 7785828

8 files changed

+249
-12
lines changed

src/Uno.UI.Tests/Windows_UI_Xaml_Markup/XamlReaderTests/Given_XamlReader.cs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,6 +1254,98 @@ public void When_StaticResource_In_ResourceDictionary()
12541254
Assert.AreEqual(b2.Color, c2);
12551255
}
12561256

1257+
[TestMethod]
1258+
public void When_StaticResource_In_Explicit_ResourceDictionary()
1259+
{
1260+
var s = GetContent(nameof(When_StaticResource_In_Explicit_ResourceDictionary));
1261+
var r = Windows.UI.Xaml.Markup.XamlReader.Load(s) as UserControl;
1262+
1263+
var panel = r.FindName("panel") as StackPanel;
1264+
Assert.IsNotNull(panel);
1265+
1266+
var c2 = (Color)panel.Resources["c2"];
1267+
var b2 = (SolidColorBrush)panel.Resources["b2"];
1268+
1269+
r.ForceLoaded();
1270+
1271+
c2 = (Color)panel.Resources["c2"];
1272+
b2 = (SolidColorBrush)panel.Resources["b2"];
1273+
1274+
Assert.AreEqual(b2.Color, c2);
1275+
}
1276+
1277+
[TestMethod]
1278+
public void When_StaticResource_In_Explicit_ResourceDictionary_And_ThemeResources()
1279+
{
1280+
var s = GetContent(nameof(When_StaticResource_In_Explicit_ResourceDictionary_And_ThemeResources));
1281+
var r = Windows.UI.Xaml.Markup.XamlReader.Load(s) as UserControl;
1282+
1283+
var panel = r.FindName("panel") as StackPanel;
1284+
Assert.IsNotNull(panel);
1285+
1286+
var c2 = (Color)panel.Resources["c2"];
1287+
var b2 = (SolidColorBrush)panel.Resources["b2"];
1288+
1289+
r.ForceLoaded();
1290+
1291+
c2 = (Color)panel.Resources["c2"];
1292+
b2 = (SolidColorBrush)panel.Resources["b2"];
1293+
1294+
var c3 = (Color)panel.Resources["c3"];
1295+
var b3 = (SolidColorBrush)panel.Resources["b3"];
1296+
1297+
Assert.AreEqual(b3.Color, c3);
1298+
}
1299+
1300+
[TestMethod]
1301+
public void When_StaticResource_In_Explicit_ResourceDictionary_And_MergedDictionaries()
1302+
{
1303+
var s = GetContent(nameof(When_StaticResource_In_Explicit_ResourceDictionary_And_MergedDictionaries));
1304+
var r = Windows.UI.Xaml.Markup.XamlReader.Load(s) as UserControl;
1305+
1306+
var panel = r.FindName("panel") as StackPanel;
1307+
Assert.IsNotNull(panel);
1308+
1309+
var c2 = (Color)panel.Resources["c2"];
1310+
var b2 = (SolidColorBrush)panel.Resources["b2"];
1311+
1312+
r.ForceLoaded();
1313+
1314+
c2 = (Color)panel.Resources["c2"];
1315+
b2 = (SolidColorBrush)panel.Resources["b2"];
1316+
1317+
Assert.AreEqual(b2.Color, c2);
1318+
1319+
var c3 = (Color)panel.Resources["c3"];
1320+
var b3 = (SolidColorBrush)panel.Resources["b3"];
1321+
1322+
Assert.AreEqual(b3.Color, c3);
1323+
1324+
var c4 = (Color)panel.Resources["c4"];
1325+
var b4 = (SolidColorBrush)panel.Resources["b4"];
1326+
1327+
Assert.AreEqual(b4.Color, c4);
1328+
}
1329+
1330+
[TestMethod]
1331+
public void When_StaticResource_MergedDictionaries_Fluent()
1332+
{
1333+
var s = GetContent(nameof(When_StaticResource_MergedDictionaries_Fluent));
1334+
var r = Windows.UI.Xaml.Markup.XamlReader.Load(s) as UserControl;
1335+
1336+
var panel = r.FindName("panel") as StackPanel;
1337+
Assert.IsNotNull(panel);
1338+
1339+
var t1 = (Color)panel.Resources["c1"];
1340+
1341+
r.ForceLoaded();
1342+
1343+
var b1 = (SolidColorBrush)panel.Resources["b1"];
1344+
1345+
Assert.AreEqual(t1, Colors.Red);
1346+
Assert.AreEqual(t1, b1.Color);
1347+
}
1348+
12571349
/// <summary>
12581350
/// XamlReader.Load the xaml and type-check result.
12591351
/// </summary>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using Windows.UI;
7+
using Windows.UI.Xaml;
8+
9+
namespace Uno.UI.Tests.Windows_UI_Xaml_Markup.XamlReaderTests
10+
{
11+
public class TestCodedResourceDictionary : ResourceDictionary
12+
{
13+
public TestCodedResourceDictionary()
14+
{
15+
this["c1"] = Colors.Red;
16+
}
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
x:Name="testPage">
4+
5+
<StackPanel x:Name="panel" Spacing="20" HorizontalAlignment="Left">
6+
<StackPanel.Resources>
7+
<ResourceDictionary>
8+
<SolidColorBrush x:Key="b1">Red</SolidColorBrush>
9+
10+
<Color x:Key="c2">Green</Color>
11+
<SolidColorBrush x:Key="b2" Color="{StaticResource c2}" />
12+
</ResourceDictionary>
13+
</StackPanel.Resources>
14+
</StackPanel>
15+
</UserControl>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
x:Name="testPage">
4+
5+
<StackPanel x:Name="panel" Spacing="20" HorizontalAlignment="Left">
6+
<StackPanel.Resources>
7+
<ResourceDictionary>
8+
<ResourceDictionary.MergedDictionaries>
9+
<ResourceDictionary>
10+
<Color x:Key="c3">Blue</Color>
11+
</ResourceDictionary>
12+
<ResourceDictionary>
13+
<Color x:Key="c4">Purple</Color>
14+
</ResourceDictionary>
15+
</ResourceDictionary.MergedDictionaries>
16+
17+
<SolidColorBrush x:Key="b1">Red</SolidColorBrush>
18+
19+
<Color x:Key="c2">Green</Color>
20+
<SolidColorBrush x:Key="b2" Color="{StaticResource c2}" />
21+
<SolidColorBrush x:Key="b3" Color="{StaticResource c3}" />
22+
<SolidColorBrush x:Key="b4" Color="{StaticResource c4}" />
23+
</ResourceDictionary>
24+
</StackPanel.Resources>
25+
</StackPanel>
26+
</UserControl>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
x:Name="testPage">
4+
5+
<StackPanel x:Name="panel" Spacing="20" HorizontalAlignment="Left">
6+
<StackPanel.Resources>
7+
<ResourceDictionary>
8+
<ResourceDictionary.ThemeDictionaries>
9+
<ResourceDictionary x:Key="Light">
10+
<Color x:Key="c3">Blue</Color>
11+
</ResourceDictionary>
12+
<ResourceDictionary x:Key="Dark">
13+
<Color x:Key="c3">Purple</Color>
14+
</ResourceDictionary>
15+
</ResourceDictionary.ThemeDictionaries>
16+
17+
<SolidColorBrush x:Key="b1">Red</SolidColorBrush>
18+
19+
<Color x:Key="c2">Green</Color>
20+
<SolidColorBrush x:Key="b2" Color="{StaticResource c2}" />
21+
<SolidColorBrush x:Key="b3" Color="{StaticResource c3}" />
22+
</ResourceDictionary>
23+
</StackPanel.Resources>
24+
</StackPanel>
25+
</UserControl>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
x:Name="testPage">
4+
5+
<StackPanel x:Name="panel" Spacing="20" HorizontalAlignment="Left">
6+
<StackPanel.Resources>
7+
<ResourceDictionary>
8+
<ResourceDictionary.MergedDictionaries>
9+
<TestCodedResourceDictionary xmlns="using:Uno.UI.Tests.Windows_UI_Xaml_Markup.XamlReaderTests" />
10+
</ResourceDictionary.MergedDictionaries>
11+
12+
<SolidColorBrush x:Key="b1" Color="{StaticResource c1}" />
13+
</ResourceDictionary>
14+
</StackPanel.Resources>
15+
</StackPanel>
16+
</UserControl>

src/Uno.UI/UI/Xaml/Markup/Reader/XamlObjectBuilder.cs

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -572,15 +572,53 @@ private void ProcessMemberElements(object instance, XamlMemberDefinition member,
572572
var addMethod = propertyInfo.PropertyType.GetMethod("Add", new[] { typeof(object), typeof(object) })
573573
?? throw new InvalidOperationException($"The property {propertyInfo} type does not provide an Add method (Line {member.LineNumber}:{member.LinePosition}");
574574

575-
if(propertyInfo.GetMethod == null)
575+
if (propertyInfo.GetMethod == null)
576576
{
577577
throw new InvalidOperationException($"The property {propertyInfo} does not provide a getter (Line {member.LineNumber}:{member.LinePosition}");
578578
}
579579

580-
var propertyInstance = propertyInfo.GetMethod.Invoke(instance, null);
580+
var targetDictionary = (ResourceDictionary)propertyInfo.GetMethod.Invoke(instance, null);
581+
582+
var dictionaryObjects = member.Objects;
583+
584+
if (member.Objects.Count == 1
585+
&& member.Objects.First() is { } innerDictionary
586+
&& TypeResolver.FindType(innerDictionary.Type) == typeof(ResourceDictionary))
587+
{
588+
if (innerDictionary.Members.FirstOrDefault(m => m.Member.Name == "ThemeDictionaries") is { } themeDictionaries)
589+
{
590+
foreach (var themeDictionary in themeDictionaries.Objects)
591+
{
592+
targetDictionary.ThemeDictionaries.Add(
593+
GetResourceKey(themeDictionary),
594+
LoadObject(themeDictionary, rootInstance));
595+
}
596+
}
597+
598+
if (innerDictionary.Members.FirstOrDefault(m => m.Member.Name == "MergedDictionaries") is { } mergedDictionaries)
599+
{
600+
foreach (var mergedDictionary in mergedDictionaries.Objects)
601+
{
602+
var newInstance = LoadObject(mergedDictionary, rootInstance);
603+
if (newInstance is ResourceDictionary instanceAsDictionary)
604+
{
605+
targetDictionary.MergedDictionaries.Add(instanceAsDictionary);
606+
}
607+
else
608+
{
609+
throw new InvalidOperationException($"An object of type {newInstance?.GetType()} is not supported on MergedDictionaries");
610+
}
611+
}
612+
}
613+
614+
if (innerDictionary.Members.FirstOrDefault(m => m.Member.Name == "_UnknownContent") is { } unknownContent)
615+
{
616+
dictionaryObjects = unknownContent.Objects;
617+
}
618+
}
581619

582620
List<IDependencyObjectStoreProvider> delayResolutionList = new();
583-
foreach (var child in member.Objects)
621+
foreach (var child in dictionaryObjects)
584622
{
585623
var item = LoadObject(child, rootInstance: rootInstance);
586624

@@ -595,21 +633,18 @@ private void ProcessMemberElements(object instance, XamlMemberDefinition member,
595633
throw new InvalidOperationException($"No target type was specified (Line {member.LineNumber}:{member.LinePosition}");
596634
}
597635

598-
addMethod.Invoke(propertyInstance, new[] { resourceKey ?? resourceTargetType, item });
636+
targetDictionary.Add(resourceKey ?? resourceTargetType, item);
599637

600638
if (HasAnyResourceMarkup(child) && item is IDependencyObjectStoreProvider provider)
601639
{
602640
delayResolutionList.Add(provider);
603641
}
604642
}
605643

606-
if (propertyInstance is ResourceDictionary dictionary)
644+
// Delay resolve static resources
645+
foreach (var delayedItem in delayResolutionList)
607646
{
608-
// Delay resolve static resources
609-
foreach (var delayedItem in delayResolutionList)
610-
{
611-
delayedItem.Store.UpdateResourceBindings(ResourceUpdateReason.StaticResourceLoading, dictionary);
612-
}
647+
delayedItem.Store.UpdateResourceBindings(ResourceUpdateReason.StaticResourceLoading, targetDictionary);
613648
}
614649
}
615650
else if (propertyInfo.SetMethod?.IsPublic == true &&

src/Uno.UI/UI/Xaml/Markup/Reader/XamlTypeResolver.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,9 +308,19 @@ public bool IsType(XamlType xamlType, string? typeName)
308308
}
309309
}
310310

311-
var fullName = isKnownNamespace ? ns?.Prefix + ":" + type.Name : type.Name;
311+
string getFullName()
312+
{
313+
if (!isKnownNamespace && type.PreferredXamlNamespace.StartsWith("using:"))
314+
{
315+
return type.PreferredXamlNamespace.TrimStart("using:") + "." + type.Name;
316+
}
317+
else
318+
{
319+
return isKnownNamespace ? ns?.Prefix + ":" + type.Name : type.Name;
320+
}
321+
}
312322

313-
return _findType(fullName);
323+
return _findType(getFullName());
314324
}
315325
else
316326
{

0 commit comments

Comments
 (0)