diff options
Diffstat (limited to 'Xamarin.Forms.Build.Tasks/SetResourcesVisitor.cs')
-rw-r--r-- | Xamarin.Forms.Build.Tasks/SetResourcesVisitor.cs | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/Xamarin.Forms.Build.Tasks/SetResourcesVisitor.cs b/Xamarin.Forms.Build.Tasks/SetResourcesVisitor.cs new file mode 100644 index 00000000..c054117c --- /dev/null +++ b/Xamarin.Forms.Build.Tasks/SetResourcesVisitor.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections; +using System.Linq; +using Mono.Cecil; +using Mono.Cecil.Cil; +using Xamarin.Forms.Xaml; + +namespace Xamarin.Forms.Build.Tasks +{ + class SetResourcesVisitor : IXamlNodeVisitor + { + public SetResourcesVisitor(ILContext context) + { + Context = context; + Module = context.Body.Method.Module; + } + + public ILContext Context { get; } + + ModuleDefinition Module { get; } + + public bool VisitChildrenFirst + { + get { return false; } + } + + public bool StopOnDataTemplate + { + get { return true; } + } + + public bool StopOnResourceDictionary + { + get { return false; } + } + + public void Visit(ValueNode node, INode parentNode) + { + } + + public void Visit(MarkupNode node, INode parentNode) + { + } + + public void Visit(ElementNode node, INode parentNode) + { + //Set Resources in ResourcesDictionaries + if (IsCollectionItem(node, parentNode) && parentNode is IElementNode) + { + // Collection element, implicit content, or implicit collection element. + CustomAttribute cpAttr; + var parentVar = Context.Variables[(IElementNode)parentNode]; + if (parentVar.VariableType.ImplementsInterface(Module.Import(typeof (IEnumerable)))) + { + if (parentVar.VariableType.FullName == "Xamarin.Forms.ResourceDictionary" && + !node.Properties.ContainsKey(XmlName.xKey)) + { + node.Accept(new SetPropertiesVisitor(Context), parentNode); + + if (node.XmlType.Name != "Style") + throw new XamlParseException("resources in ResourceDictionary require a x:Key attribute", node); + + //if this node is an IMarkupExtension, invoke ProvideValue() and replace the variable + var vardef = Context.Variables[node]; + var vardefref = new VariableDefinitionReference(vardef); + Context.IL.Append(SetPropertiesVisitor.ProvideValue(vardefref, Context, Module, node)); + if (vardef != vardefref.VariableDefinition) + { + vardef = vardefref.VariableDefinition; + Context.Body.Variables.Add(vardef); + Context.Variables[node] = vardef; + } + + Context.IL.Emit(OpCodes.Ldloc, parentVar); + Context.IL.Emit(OpCodes.Ldloc, Context.Variables[node]); + Context.IL.Emit(OpCodes.Callvirt, + Module.Import( + Module.Import(typeof (ResourceDictionary)) + .Resolve() + .Methods.Single(md => md.Name == "Add" && md.Parameters.Count == 1))); + } + else if (parentVar.VariableType.FullName == "Xamarin.Forms.ResourceDictionary" && + node.Properties.ContainsKey(XmlName.xKey)) + { + node.Accept(new SetPropertiesVisitor(Context), parentNode); + + //if this node is an IMarkupExtension, invoke ProvideValue() and replace the variable + var vardef = Context.Variables[node]; + var vardefref = new VariableDefinitionReference(vardef); + Context.IL.Append(SetPropertiesVisitor.ProvideValue(vardefref, Context, Module, node)); + if (vardef != vardefref.VariableDefinition) + { + vardef = vardefref.VariableDefinition; + Context.Body.Variables.Add(vardef); + Context.Variables[node] = vardef; + } + + // IL_0013: ldloc.0 + // IL_0014: ldstr "key" + // IL_0019: ldstr "foo" + // IL_001e: callvirt instance void class [Xamarin.Forms.Core]Xamarin.Forms.ResourceDictionary::Add(string, object) + Context.IL.Emit(OpCodes.Ldloc, parentVar); + Context.IL.Emit(OpCodes.Ldstr, (node.Properties[XmlName.xKey] as ValueNode).Value as string); + var varDef = Context.Variables[node]; + Context.IL.Emit(OpCodes.Ldloc, varDef); + if (varDef.VariableType.IsValueType) + Context.IL.Emit(OpCodes.Box, Module.Import(varDef.VariableType)); + Context.IL.Emit(OpCodes.Callvirt, + Module.Import( + Module.Import(typeof (ResourceDictionary)) + .Resolve() + .Methods.Single(md => md.Name == "Add" && md.Parameters.Count == 2))); + } + } + } + + //Set ResourcesDictionaries to their parents + XmlName propertyName; + if (SetPropertiesVisitor.TryGetPropertyName(node, parentNode, out propertyName) && + (propertyName.LocalName == "Resources" || propertyName.LocalName.EndsWith(".Resources", StringComparison.Ordinal)) && + Context.Variables[node].VariableType.FullName == "Xamarin.Forms.ResourceDictionary") + SetPropertiesVisitor.SetPropertyValue(Context.Variables[(IElementNode)parentNode], propertyName, node, Context, node); + } + + public void Visit(RootNode node, INode parentNode) + { + } + + public void Visit(ListNode node, INode parentNode) + { + } + + static bool IsCollectionItem(INode node, INode parentNode) + { + var parentList = parentNode as IListNode; + if (parentList == null) + return false; + return parentList.CollectionItems.Contains(node); + } + } +}
\ No newline at end of file |