Skip to content

Commit d887a43

Browse files
committed
feat: Add XamlReader support for theme dictionaries
1 parent 898acca commit d887a43

File tree

3 files changed

+160
-4
lines changed

3 files changed

+160
-4
lines changed

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -948,6 +948,23 @@ public void When_xName_Reload()
948948
Assert.AreEqual(Button2_property_public, SUT.Button2_property_public);
949949
}
950950

951+
[TestMethod]
952+
public void When_ResourceDictionary_Colors()
953+
{
954+
var s = GetContent(nameof(When_ResourceDictionary_Colors));
955+
var r = Windows.UI.Xaml.Markup.XamlReader.Load(s) as ResourceDictionary;
956+
957+
var lightTheme = r.ThemeDictionaries["Light"] as ResourceDictionary;
958+
Assert.IsNotNull(lightTheme);
959+
960+
Assert.AreEqual(Windows.UI.Colors.Red, lightTheme["MaterialPrimaryColor"]);
961+
962+
var darkTheme = r.ThemeDictionaries["Dark"] as ResourceDictionary;
963+
Assert.IsNotNull(darkTheme);
964+
965+
Assert.AreEqual(Windows.UI.Colors.White, darkTheme["MaterialOnPrimaryColor"]);
966+
}
967+
951968
private string GetContent(string testName)
952969
{
953970
var assembly = this.GetType().Assembly;
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
3+
4+
<ResourceDictionary.ThemeDictionaries>
5+
<!-- Light Theme -->
6+
<ResourceDictionary x:Key="Light">
7+
<!-- Primary -->
8+
<Color x:Key="MaterialPrimaryColor">#FF0000</Color>
9+
<Color x:Key="MaterialPrimaryVariantDarkColor">#04488C</Color>
10+
<Color x:Key="MaterialPrimaryVariantLightColor">#E3EFFB</Color>
11+
12+
<!-- OnPrimary -->
13+
<Color x:Key="MaterialOnPrimaryColor">#FFFFFF</Color>
14+
15+
<!-- Secondary -->
16+
<Color x:Key="MaterialSecondaryColor">#FEB839</Color>
17+
<Color x:Key="MaterialSecondaryVariantDarkColor">#FFA502</Color>
18+
<Color x:Key="MaterialSecondaryVariantLightColor">#FFD487</Color>
19+
20+
<!-- OnSecondary -->
21+
<Color x:Key="MaterialOnSecondaryColor">#000000</Color>
22+
23+
<!-- Background -->
24+
<Color x:Key="MaterialBackgroundColor">#F0F0F0</Color>
25+
26+
<!-- OnBackground -->
27+
<Color x:Key="MaterialOnBackgroundColor">#000000</Color>
28+
29+
<!-- Surface -->
30+
<Color x:Key="MaterialSurfaceColor">#FFFFFF</Color>
31+
32+
<!-- OnSurface -->
33+
<Color x:Key="MaterialOnSurfaceColor">#000000</Color>
34+
35+
<!-- Error -->
36+
<Color x:Key="MaterialErrorColor">#B00020</Color>
37+
38+
<!-- OnError -->
39+
<Color x:Key="MaterialOnErrorColor">#FFFFFF</Color>
40+
</ResourceDictionary>
41+
42+
<!-- Dark Theme -->
43+
<ResourceDictionary x:Key="Dark">
44+
<!-- Primary -->
45+
<Color x:Key="MaterialPrimaryColor">#2F81D8</Color>
46+
<Color x:Key="MaterialPrimaryVariantDarkColor">#04488C</Color>
47+
<Color x:Key="MaterialPrimaryVariantLightColor">#E3EFFB</Color>
48+
49+
<!-- OnPrimary -->
50+
<Color x:Key="MaterialOnPrimaryColor">#FFFFFF</Color>
51+
52+
<!-- Secondary -->
53+
<Color x:Key="MaterialSecondaryColor">#FEB839</Color>
54+
<Color x:Key="MaterialSecondaryVariantDarkColor">#FFA502</Color>
55+
<Color x:Key="MaterialSecondaryVariantLightColor">#FFD487</Color>
56+
57+
<!-- OnSecondary -->
58+
<Color x:Key="MaterialOnSecondaryColor">#000000</Color>
59+
60+
<!-- Background -->
61+
<Color x:Key="MaterialBackgroundColor">#000000</Color>
62+
63+
<!-- OnBackground -->
64+
<Color x:Key="MaterialOnBackgroundColor">#FFFFFF</Color>
65+
66+
<!-- Surface -->
67+
<Color x:Key="MaterialSurfaceColor">#0F0F0F</Color>
68+
69+
<!-- OnSurface -->
70+
<Color x:Key="MaterialOnSurfaceColor">#FFFFFF</Color>
71+
72+
<!-- Error -->
73+
<Color x:Key="MaterialErrorColor">#B2213C</Color>
74+
75+
<!-- OnError -->
76+
<Color x:Key="MaterialOnErrorColor">#FFFFFF</Color>
77+
</ResourceDictionary>
78+
79+
</ResourceDictionary.ThemeDictionaries>
80+
81+
</ResourceDictionary>

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

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,14 @@ private void ProcessMemberElements(object instance, XamlMemberDefinition member,
561561

562562
if (propertyInstance != null)
563563
{
564-
AddCollectionItems(propertyInstance, member.Objects, rootInstance);
564+
if (propertyInstance is IDictionary<object, object> propertyInstanceAsDictionary)
565+
{
566+
AddGenericDictionaryItems(propertyInstanceAsDictionary, member.Objects, rootInstance);
567+
}
568+
else
569+
{
570+
AddCollectionItems(propertyInstance, member.Objects, rootInstance);
571+
}
565572
}
566573
else
567574
{
@@ -848,16 +855,67 @@ private static bool IsMarkupExtension(XamlMemberDefinition member)
848855
)
849856
.Any();
850857

858+
private void AddGenericDictionaryItems(
859+
IDictionary<object, object> dictionary,
860+
IEnumerable<XamlObjectDefinition> nonBindingObjects,
861+
object rootInstance)
862+
{
863+
foreach (var child in nonBindingObjects)
864+
{
865+
var item = LoadObject(child, rootInstance: rootInstance);
866+
867+
var resourceKey = GetResourceKey(child);
868+
869+
if (resourceKey != null && item != null)
870+
{
871+
dictionary[resourceKey] = item;
872+
}
873+
}
874+
}
875+
876+
private void AddDictionaryItems(object collectionInstance, IEnumerable<XamlObjectDefinition> nonBindingObjects, object rootInstance)
877+
{
878+
MethodInfo? addMethodInfo = null;
879+
880+
foreach (var child in nonBindingObjects)
881+
{
882+
var item = LoadObject(child, rootInstance: rootInstance);
883+
884+
if (addMethodInfo == null)
885+
{
886+
addMethodInfo = collectionInstance
887+
.GetType()
888+
.GetMethods(BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.Public)
889+
.Where(m => m.Name == "set_Item")
890+
.FirstOrDefault(m => m.GetParameters() is { Length: 1 } p
891+
&& (item?.GetType() ?? typeof(object)).Is(p[0].ParameterType))
892+
?? throw new InvalidOperationException($"The type does {collectionInstance.GetType()} contains an Add({item?.GetType()}) method");
893+
}
894+
895+
addMethodInfo.Invoke(collectionInstance, new[] { item });
896+
}
897+
}
898+
851899
private void AddCollectionItems(object collectionInstance, IEnumerable<XamlObjectDefinition> nonBindingObjects, object rootInstance)
852900
{
853-
var addMethod = collectionInstance.GetType().GetMethod("Add")
854-
?? throw new InvalidOperationException($"The type {collectionInstance.GetType()} contains an Add method");
901+
MethodInfo? addMethodInfo = null;
855902

856903
foreach (var child in nonBindingObjects)
857904
{
858905
var item = LoadObject(child, rootInstance: rootInstance);
859906

860-
addMethod.Invoke(collectionInstance, new[] { item });
907+
if (addMethodInfo == null)
908+
{
909+
addMethodInfo = collectionInstance
910+
.GetType()
911+
.GetMethods(BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.Public)
912+
.Where(m => m.Name == "Add")
913+
.FirstOrDefault(m => m.GetParameters() is { Length: 1 } p
914+
&& (item?.GetType() ?? typeof(object)).Is(p[0].ParameterType))
915+
?? throw new InvalidOperationException($"The type does {collectionInstance.GetType()} contains an Add({item?.GetType()}) method");
916+
}
917+
918+
addMethodInfo.Invoke(collectionInstance, new[] { item });
861919
}
862920
}
863921

0 commit comments

Comments
 (0)