public void Visit(ElementNode node, INode parentNode) { if (!Values.TryGetValue(node, out var value) && Context.ExceptionHandler != null) { return; } //Set RD to VE if (typeof(ResourceDictionary).IsAssignableFrom(Context.Types[node]) && ApplyPropertiesVisitor.TryGetPropertyName(node, parentNode, out XmlName propertyName)) { if ((propertyName.LocalName == "Resources" || propertyName.LocalName.EndsWith(".Resources", StringComparison.Ordinal)) && value is ResourceDictionary) { var source = Values[parentNode]; ApplyPropertiesVisitor.SetPropertyValue(source, propertyName, value, Context.RootElement, node, Context, node); return; } } //Only proceed further if the node is a keyless RD if (parentNode is IElementNode && Context.Types.TryGetValue((IElementNode)parentNode, out var parentType) && typeof(ResourceDictionary).IsAssignableFrom(parentType) && !((IElementNode)parentNode).Properties.ContainsKey(XmlName.xKey)) { node.Accept(new ApplyPropertiesVisitor(Context, stopOnResourceDictionary: false), parentNode); } else if (parentNode is ListNode && typeof(ResourceDictionary).IsAssignableFrom(Context.Types[((IElementNode)parentNode.Parent)]) && !((IElementNode)parentNode.Parent).Properties.ContainsKey(XmlName.xKey)) { node.Accept(new ApplyPropertiesVisitor(Context, stopOnResourceDictionary: false), parentNode); } }
static void SetDataTemplate(IElementNode parentNode, ElementNode node, ILContext parentContext, IXmlLineInfo xmlLineInfo) { var parentVar = parentContext.Variables[parentNode]; //Push the DataTemplate to the stack, for setting the template parentContext.IL.Emit(OpCodes.Ldloc, parentVar); //Create nested class // .class nested private auto ansi sealed beforefieldinit '<Main>c__AnonStorey0' // extends [mscorlib]System.Object var module = parentContext.Body.Method.Module; var anonType = new TypeDefinition( null, "<" + parentContext.Body.Method.Name + ">_anonXamlCDataTemplate_" + dtcount++, TypeAttributes.BeforeFieldInit | TypeAttributes.Sealed | TypeAttributes.NestedPrivate) { BaseType = module.TypeSystem.Object }; parentContext.Body.Method.DeclaringType.NestedTypes.Add(anonType); var ctor = anonType.AddDefaultConstructor(); var loadTemplate = new MethodDefinition("LoadDataTemplate", MethodAttributes.Assembly | MethodAttributes.HideBySig, module.TypeSystem.Object); anonType.Methods.Add(loadTemplate); var parentValues = new FieldDefinition("parentValues", FieldAttributes.Assembly, module.Import(typeof (object[]))); anonType.Fields.Add(parentValues); TypeReference rootType = null; var vdefRoot = parentContext.Root as VariableDefinition; if (vdefRoot != null) rootType = vdefRoot.VariableType; var fdefRoot = parentContext.Root as FieldDefinition; if (fdefRoot != null) rootType = fdefRoot.FieldType; var root = new FieldDefinition("root", FieldAttributes.Assembly, rootType); anonType.Fields.Add(root); //Fill the loadTemplate Body var templateIl = loadTemplate.Body.GetILProcessor(); templateIl.Emit(OpCodes.Nop); var templateContext = new ILContext(templateIl, loadTemplate.Body, parentValues) { Root = root }; node.Accept(new CreateObjectVisitor(templateContext), null); node.Accept(new SetNamescopesAndRegisterNamesVisitor(templateContext), null); node.Accept(new SetFieldVisitor(templateContext), null); node.Accept(new SetResourcesVisitor(templateContext), null); node.Accept(new SetPropertiesVisitor(templateContext), null); templateIl.Emit(OpCodes.Ldloc, templateContext.Variables[node]); templateIl.Emit(OpCodes.Ret); //Instanciate nested class var parentIl = parentContext.IL; parentIl.Emit(OpCodes.Newobj, ctor); //Copy required local vars parentIl.Emit(OpCodes.Dup); //Duplicate the nestedclass instance parentIl.Append(node.PushParentObjectsArray(parentContext)); parentIl.Emit(OpCodes.Stfld, parentValues); parentIl.Emit(OpCodes.Dup); //Duplicate the nestedclass instance if (parentContext.Root is VariableDefinition) parentIl.Emit(OpCodes.Ldloc, parentContext.Root as VariableDefinition); else if (parentContext.Root is FieldDefinition) { parentIl.Emit(OpCodes.Ldarg_0); parentIl.Emit(OpCodes.Ldfld, parentContext.Root as FieldDefinition); } else throw new InvalidProgramException(); parentIl.Emit(OpCodes.Stfld, root); //SetDataTemplate parentIl.Emit(OpCodes.Ldftn, loadTemplate); var funcCtor = module.Import(typeof (Func<>)) .MakeGenericInstanceType(module.TypeSystem.Object) .Resolve() .Methods.First(md => md.IsConstructor && md.Parameters.Count == 2) .MakeGeneric(module.TypeSystem.Object); parentIl.Emit(OpCodes.Newobj, module.Import(funcCtor)); var propertySetter = module.Import(typeof (IDataTemplate)).Resolve().Properties.First(p => p.Name == "LoadTemplate").SetMethod; parentContext.IL.Emit(OpCodes.Callvirt, module.Import(propertySetter)); }
public void Visit(ElementNode node, INode parentNode) { var value = Values[node]; var parentElement = parentNode as IElementNode; var markupExtension = value as IMarkupExtension; var valueProvider = value as IValueProvider; //Set Resources in ResourcesDictionaries if (IsCollectionItem(node, parentNode) && parentNode is IElementNode) { if (typeof(IEnumerable).IsAssignableFrom(Context.Types[parentElement])) { var source = Values[parentNode]; if (typeof(ResourceDictionary).IsAssignableFrom(Context.Types[parentElement]) && value is Style && !node.Properties.ContainsKey(XmlName.xKey)) { node.Accept(new ApplyPropertiesVisitor(Context), parentNode); if (markupExtension != null) { var serviceProvider = new XamlServiceProvider(node, Context); value = markupExtension.ProvideValue(serviceProvider); } if (valueProvider != null) { var serviceProvider = new XamlServiceProvider(node, Context); value = valueProvider.ProvideValue(serviceProvider); } ((ResourceDictionary)source).Add(value as Style); } else if (typeof(ResourceDictionary).IsAssignableFrom(Context.Types[parentElement]) && !node.Properties.ContainsKey(XmlName.xKey)) { throw new XamlParseException("resources in ResourceDictionary require a x:Key attribute", node); } else if (typeof(ResourceDictionary).IsAssignableFrom(Context.Types[parentElement]) && node.Properties.ContainsKey(XmlName.xKey)) { node.Accept(new ApplyPropertiesVisitor(Context), parentNode); if (markupExtension != null) { var serviceProvider = new XamlServiceProvider(node, Context); value = markupExtension.ProvideValue(serviceProvider); } if (valueProvider != null) { var serviceProvider = new XamlServiceProvider(node, Context); value = valueProvider.ProvideValue(serviceProvider); } ((ResourceDictionary)source).Add((string)(((ValueNode)node.Properties[XmlName.xKey]).Value), value); } } } //Set RD to VE XmlName propertyName; if (ApplyPropertiesVisitor.TryGetPropertyName(node, parentNode, out propertyName)) { if ((propertyName.LocalName == "Resources" || propertyName.LocalName.EndsWith(".Resources", StringComparison.Ordinal)) && value is ResourceDictionary) { var source = Values[parentNode]; ApplyPropertiesVisitor.SetPropertyValue(source, propertyName, value, Context.RootElement, node, Context, node); } } }
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" || parentVar.VariableType.Resolve().BaseType.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" || parentVar.VariableType.Resolve().BaseType.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" || Context.Variables[node].VariableType.Resolve().BaseType.FullName == "Xamarin.Forms.ResourceDictionary")) SetPropertiesVisitor.SetPropertyValue(Context.Variables[(IElementNode)parentNode], propertyName, node, Context, node); }