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);
                }
            }
        }
Esempio n. 4
0
		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);
		}