Esempio n. 1
0
		public void Visit(ElementNode node, INode parentNode)
		{
			var ns = parentNode == null || IsDataTemplate(node, parentNode) || IsStyle(node, parentNode)
				? new NameScope()
				: scopes[parentNode];
			node.Namescope = ns;
			scopes[node] = ns;
		}
Esempio n. 2
0
		public void Visit(ElementNode node, INode parentNode)
		{
			action(node, parentNode);
		}
		public void Visit(ElementNode node, INode parentNode)
		{
			if (node.SkipPrefix(node.NamespaceResolver.LookupPrefix(node.NamespaceURI)))
				return;

			var value = Values[node];
			var parentElement = parentNode as IElementNode;
			var markupExtension = value as IMarkupExtension;
			var valueProvider = value as IValueProvider;

			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);
			}

			XmlName propertyName;
			if (TryGetPropertyName(node, parentNode, out propertyName))
			{
				if (Skips.Contains(propertyName))
					return;
				if (parentElement.SkipProperties.Contains(propertyName))
					return;

				var source = Values[parentNode];

				if (propertyName == XmlName._CreateContent && source is ElementTemplate)
					SetTemplate(source as ElementTemplate, node);
				else
					SetPropertyValue(source, propertyName, value, Context.RootElement, node, Context, node);
			}
			else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode)
			{
				// Collection element, implicit content, or implicit collection element.
				string contentProperty;
				if (typeof (IEnumerable).GetTypeInfo().IsAssignableFrom(Context.Types[parentElement].GetTypeInfo()))
				{
					var source = Values[parentNode];
					if (!(typeof (ResourceDictionary).IsAssignableFrom(Context.Types[parentElement])))
					{
						var addMethod =
							Context.Types[parentElement].GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1);
						addMethod.Invoke(source, new[] { value });
					}
				}
				else if ((contentProperty = GetContentPropertyName(Context.Types[parentElement].GetTypeInfo())) != null)
				{
					var name = new XmlName(node.NamespaceURI, contentProperty);
					if (Skips.Contains(name))
						return;
					if (parentElement.SkipProperties.Contains(propertyName))
						return;

					var source = Values[parentNode];
					SetPropertyValue(source, name, value, Context.RootElement, node, Context, node);
				}
			}
			else if (IsCollectionItem(node, parentNode) && parentNode is ListNode)
			{
				var parentList = (ListNode)parentNode;
				var source = Values[parentNode.Parent];

				if (Skips.Contains(parentList.XmlName))
					return;

				var elementType = source.GetType();
				var localname = parentList.XmlName.LocalName;

				GetRealNameAndType(ref elementType, parentList.XmlName.NamespaceURI, ref localname, Context, node);

				PropertyInfo propertyInfo = null;
				try
				{
					propertyInfo = elementType.GetRuntimeProperty(localname);
				}
				catch (AmbiguousMatchException)
				{
					// Get most derived instance of property
					foreach (var property in elementType.GetRuntimeProperties().Where(prop => prop.Name == localname))
					{
						if (propertyInfo == null || propertyInfo.DeclaringType.IsAssignableFrom(property.DeclaringType))
							propertyInfo = property;
					}
				}
				if (propertyInfo == null)
					throw new XamlParseException(string.Format("Property {0} not found", localname), node);
				MethodInfo getter;
				if (!propertyInfo.CanRead || (getter = propertyInfo.GetMethod) == null)
					throw new XamlParseException(string.Format("Property {0} does not have an accessible getter", localname), node);
				IEnumerable collection;
				if ((collection = getter.Invoke(source, new object[] { }) as IEnumerable) == null)
					throw new XamlParseException(string.Format("Property {0} is null or is not IEnumerable", localname), node);
				MethodInfo addMethod;
				if (
					(addMethod =
						collection.GetType().GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1)) == null)
					throw new XamlParseException(string.Format("Value of {0} does not have a Add() method", localname), node);

				addMethod.Invoke(collection, new[] { Values[node] });
			}
		}
		public void Visit(ElementNode node, INode parentNode)
		{
			if (node.SkipPrefix((node.NamespaceResolver ?? parentNode.NamespaceResolver)?.LookupPrefix(node.NamespaceURI)))
				return;

			//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(ProvideValue(vardefref, Context, Module, node));
			if (vardef != vardefref.VariableDefinition)
			{
				vardef = vardefref.VariableDefinition;
				Context.Body.Variables.Add(vardef);
				Context.Variables[node] = vardef;
			}

			XmlName propertyName;
			if (TryGetPropertyName(node, parentNode, out propertyName))
			{
				if (skips.Contains(propertyName))
					return;

				if (propertyName == XmlName._CreateContent)
					SetDataTemplate((IElementNode)parentNode, node, Context, node);
				else
					SetPropertyValue(Context.Variables[(IElementNode)parentNode], propertyName, node, Context, node);
			}
			else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode)
			{
				// Collection element, implicit content, or implicit collection element.
				string contentProperty;
				var parentVar = Context.Variables[(IElementNode)parentNode];
				if (parentVar.VariableType.ImplementsInterface(Module.Import(typeof (IEnumerable))))
				{
					var elementType = parentVar.VariableType;
					if (elementType.FullName != "Xamarin.Forms.ResourceDictionary" && elementType.Resolve().BaseType.FullName != "Xamarin.Forms.ResourceDictionary")
					{
						var adderTuple = elementType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, Module).First();
						var adderRef = Module.Import(adderTuple.Item1);
						adderRef = Module.Import(adderRef.ResolveGenericParameters(adderTuple.Item2, Module));

						Context.IL.Emit(OpCodes.Ldloc, parentVar);
						Context.IL.Emit(OpCodes.Ldloc, vardef);
						Context.IL.Emit(OpCodes.Callvirt, adderRef);
						if (adderRef.ReturnType.FullName != "System.Void")
							Context.IL.Emit(OpCodes.Pop);
					}
				}
				else if ((contentProperty = GetContentProperty(parentVar.VariableType)) != null)
				{
					var name = new XmlName(node.NamespaceURI, contentProperty);
					if (skips.Contains(name))
						return;
					SetPropertyValue(Context.Variables[(IElementNode)parentNode], name, node, Context, node);
				}
			}
			else if (IsCollectionItem(node, parentNode) && parentNode is ListNode)
			{
				//				IL_000d:  ldloc.2 
				//				IL_000e:  callvirt instance class [mscorlib]System.Collections.Generic.IList`1<!0> class [Xamarin.Forms.Core]Xamarin.Forms.Layout`1<class [Xamarin.Forms.Core]Xamarin.Forms.View>::get_Children()
				//				IL_0013:  ldloc.0 
				//				IL_0014:  callvirt instance void class [mscorlib]System.Collections.Generic.ICollection`1<class [Xamarin.Forms.Core]Xamarin.Forms.View>::Add(!0)

				var parentList = (ListNode)parentNode;
				var parent = Context.Variables[((IElementNode)parentNode.Parent)];

				if (skips.Contains(parentList.XmlName))
					return;

				var elementType = parent.VariableType;
				var localname = parentList.XmlName.LocalName;

				GetNameAndTypeRef(ref elementType, parentList.XmlName.NamespaceURI, ref localname, Context, node);

				TypeReference propertyDeclaringType;
				var property = elementType.GetProperty(pd => pd.Name == localname, out propertyDeclaringType);
				MethodDefinition propertyGetter;

				if (property != null && (propertyGetter = property.GetMethod) != null && propertyGetter.IsPublic)
				{
					var propertyGetterRef = Module.Import(propertyGetter);
					propertyGetterRef = Module.Import(propertyGetterRef.ResolveGenericParameters(propertyDeclaringType, Module));
					var propertyType = propertyGetterRef.ReturnType.ResolveGenericParameters(propertyDeclaringType);

					var adderTuple = propertyType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, Module).First();
					var adderRef = Module.Import(adderTuple.Item1);
					adderRef = Module.Import(adderRef.ResolveGenericParameters(adderTuple.Item2, Module));

					Context.IL.Emit(OpCodes.Ldloc, parent);
					Context.IL.Emit(OpCodes.Callvirt, propertyGetterRef);
					Context.IL.Emit(OpCodes.Ldloc, vardef);
					Context.IL.Emit(OpCodes.Callvirt, adderRef);
					if (adderRef.ReturnType.FullName != "System.Void")
						Context.IL.Emit(OpCodes.Pop);
				}
			}
		}
		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 static IEnumerable<Instruction> ProvideValue(VariableDefinitionReference vardefref, ILContext context,
			ModuleDefinition module, ElementNode node)
		{
			GenericInstanceType markupExtension;
			IList<TypeReference> genericArguments;
			if (vardefref.VariableDefinition.VariableType.FullName == "Xamarin.Forms.Xaml.ArrayExtension" &&
			    vardefref.VariableDefinition.VariableType.ImplementsGenericInterface("Xamarin.Forms.Xaml.IMarkupExtension`1",
				    out markupExtension, out genericArguments))
			{
				var markExt = markupExtension.Resolve();
				var provideValueInfo = markExt.Methods.First(md => md.Name == "ProvideValue");
				var provideValue = module.Import(provideValueInfo);
				provideValue =
					module.Import(provideValue.MakeGeneric(markupExtension.GenericArguments.Select(tr => module.Import(tr)).ToArray()));

				var typeNode = node.Properties[new XmlName("", "Type")];
				TypeReference arrayTypeRef;
				if (context.TypeExtensions.TryGetValue(typeNode, out arrayTypeRef))
					vardefref.VariableDefinition = new VariableDefinition(module.Import(arrayTypeRef.MakeArrayType()));
				else
					vardefref.VariableDefinition = new VariableDefinition(module.Import(genericArguments.First()));
				yield return Instruction.Create(OpCodes.Ldloc, context.Variables[node]);
				foreach (var instruction in node.PushServiceProvider(context))
					yield return instruction;
				yield return Instruction.Create(OpCodes.Callvirt, provideValue);

				if (arrayTypeRef != null)
					yield return Instruction.Create(OpCodes.Castclass, module.Import(arrayTypeRef.MakeArrayType()));
				yield return Instruction.Create(OpCodes.Stloc, vardefref.VariableDefinition);
			}
			else if (vardefref.VariableDefinition.VariableType.ImplementsGenericInterface("Xamarin.Forms.Xaml.IMarkupExtension`1",
				out markupExtension, out genericArguments))
			{
				var markExt = markupExtension.Resolve();
				var provideValueInfo = markExt.Methods.First(md => md.Name == "ProvideValue");
				var provideValue = module.Import(provideValueInfo);
				provideValue =
					module.Import(provideValue.MakeGeneric(markupExtension.GenericArguments.Select(tr => module.Import(tr)).ToArray()));

				vardefref.VariableDefinition = new VariableDefinition(module.Import(genericArguments.First()));
				yield return Instruction.Create(OpCodes.Ldloc, context.Variables[node]);
				foreach (var instruction in node.PushServiceProvider(context))
					yield return instruction;
				yield return Instruction.Create(OpCodes.Callvirt, provideValue);
				yield return Instruction.Create(OpCodes.Stloc, vardefref.VariableDefinition);
			}
			else if (context.Variables[node].VariableType.ImplementsInterface(module.Import(typeof (IMarkupExtension))))
			{
				var markExt = module.Import(typeof (IMarkupExtension)).Resolve();
				var provideValueInfo = markExt.Methods.First(md => md.Name == "ProvideValue");
				var provideValue = module.Import(provideValueInfo);

				vardefref.VariableDefinition = new VariableDefinition(module.TypeSystem.Object);
				yield return Instruction.Create(OpCodes.Ldloc, context.Variables[node]);
				foreach (var instruction in node.PushServiceProvider(context))
					yield return instruction;
				yield return Instruction.Create(OpCodes.Callvirt, provideValue);
				yield return Instruction.Create(OpCodes.Stloc, vardefref.VariableDefinition);
			}
			else if (context.Variables[node].VariableType.ImplementsInterface(module.Import(typeof (IValueProvider))))
			{
				var markExt = module.Import(typeof (IValueProvider)).Resolve();
				var provideValueInfo = markExt.Methods.First(md => md.Name == "ProvideValue");
				var provideValue = module.Import(provideValueInfo);

				vardefref.VariableDefinition = new VariableDefinition(module.TypeSystem.Object);
				yield return Instruction.Create(OpCodes.Ldloc, context.Variables[node]);
				foreach (var instruction in node.PushServiceProvider(context))
					yield return instruction;
				yield return Instruction.Create(OpCodes.Callvirt, provideValue);
				yield return Instruction.Create(OpCodes.Stloc, vardefref.VariableDefinition);
			}
		}
		public void Visit(ElementNode node, INode parentNode)
		{
		}
Esempio n. 8
0
		public void Visit(ElementNode node, INode parentNode)
		{
			object value = null;

			if (node.SkipPrefix(node.NamespaceResolver.LookupPrefix(node.NamespaceURI)))
				return;

			XamlParseException xpe;
			var type = XamlParser.GetElementType(node.XmlType, node, Context.RootElement?.GetType().GetTypeInfo().Assembly,
				out xpe);
			if (xpe != null)
				throw xpe;

			Context.Types[node] = type;
			string ctorargname;
			if (IsXaml2009LanguagePrimitive(node))
				value = CreateLanguagePrimitive(type, node);
			else if (node.Properties.ContainsKey(XmlName.xArguments) || node.Properties.ContainsKey(XmlName.xFactoryMethod))
				value = CreateFromFactory(type, node);
			else if (
				type.GetTypeInfo()
					.DeclaredConstructors.Any(
						ci =>
							ci.IsPublic && ci.GetParameters().Length != 0 &&
							ci.GetParameters().All(pi => pi.CustomAttributes.Any(attr => attr.AttributeType == typeof (ParameterAttribute)))) &&
				ValidateCtorArguments(type, node, out ctorargname))
				value = CreateFromParameterizedConstructor(type, node);
			else if (!type.GetTypeInfo().DeclaredConstructors.Any(ci => ci.IsPublic && ci.GetParameters().Length == 0) &&
			         !ValidateCtorArguments(type, node, out ctorargname))
			{
				throw new XamlParseException(
					String.Format("The Property {0} is required to create a {1} object.", ctorargname, type.FullName), node);
			}
			else
			{
				//this is a trick as the DataTemplate parameterless ctor is internal, and we can't CreateInstance(..., false) on WP7
				try
				{
					if (type == typeof (DataTemplate))
						value = new DataTemplate();
					if (type == typeof (ControlTemplate))
						value = new ControlTemplate();
					if (value == null && node.CollectionItems.Any() && node.CollectionItems.First() is ValueNode)
					{
						var serviceProvider = new XamlServiceProvider(node, Context);
						var converted = ((ValueNode)node.CollectionItems.First()).Value.ConvertTo(type, () => type.GetTypeInfo(),
							serviceProvider);
						if (converted != null && converted.GetType() == type)
							value = converted;
					}
					if (value == null)
						value = Activator.CreateInstance(type);
				}
				catch (TargetInvocationException e)
				{
					if (e.InnerException is XamlParseException || e.InnerException is XmlException)
						throw e.InnerException;
					throw;
				}
			}

			Values[node] = value;

			var typeExtension = value as TypeExtension;
			if (typeExtension != null)
			{
				var serviceProvider = new XamlServiceProvider(node, Context);

				var visitor = new ApplyPropertiesVisitor(Context);
				foreach (var cnode in node.Properties.Values.ToList())
					cnode.Accept(visitor, node);
				foreach (var cnode in node.CollectionItems)
					cnode.Accept(visitor, node);

				value = typeExtension.ProvideValue(serviceProvider);

				node.Properties.Clear();
				node.CollectionItems.Clear();

				Values[node] = value;
			}

			if (value is BindableObject)
				NameScope.SetNameScope(value as BindableObject, node.Namescope);
		}
Esempio n. 9
0
		static INode ReadNode(XmlReader reader, bool nested = false)
		{
			var skipFirstRead = nested;
			Debug.Assert(reader.NodeType == XmlNodeType.Element);
			var name = reader.Name;
			List<INode> nodes = new List<INode>();
			INode node = null;

			while (skipFirstRead || reader.Read())
			{
				skipFirstRead = false;

				switch (reader.NodeType)
				{
					case XmlNodeType.EndElement:
						Debug.Assert(reader.Name == name);
						if (nodes.Count == 0) //Empty element
							return null;
						if (nodes.Count == 1)
							return nodes[0];
						return new ListNode(nodes, (IXmlNamespaceResolver)reader, ((IXmlLineInfo)reader).LineNumber,
							((IXmlLineInfo)reader).LinePosition);
					case XmlNodeType.Element:
						var isEmpty = reader.IsEmptyElement && reader.Name == name;
						var elementName = reader.Name;
						var elementNsUri = reader.NamespaceURI;
						var elementXmlInfo = (IXmlLineInfo)reader;

						var attributes = ParseXamlAttributes(reader);

						IList<XmlType> typeArguments = null;
						if (attributes.Any(kvp => kvp.Key == XmlName.xTypeArguments))
						{
							typeArguments =
								((ValueNode)attributes.First(kvp => kvp.Key == XmlName.xTypeArguments).Value).Value as IList<XmlType>;
						}

						node = new ElementNode(new XmlType(elementNsUri, elementName, typeArguments), elementNsUri,
							reader as IXmlNamespaceResolver, elementXmlInfo.LineNumber, elementXmlInfo.LinePosition);
						((IElementNode)node).Properties.AddRange(attributes);

						ParseXamlElementFor((IElementNode)node, reader);
						nodes.Add(node);
						if (isEmpty || nested)
							return node;
						break;
					case XmlNodeType.Text:
						node = new ValueNode(reader.Value.Trim(), (IXmlNamespaceResolver)reader, ((IXmlLineInfo)reader).LineNumber,
							((IXmlLineInfo)reader).LinePosition);
						nodes.Add(node);
						break;
					case XmlNodeType.Whitespace:
						break;
					default:
						Debug.WriteLine("Unhandled node {0} {1} {2}", reader.NodeType, reader.Name, reader.Value);
						break;
				}
			}
			throw new XamlParseException("Closing PropertyElement expected", (IXmlLineInfo)reader);
		}
Esempio n. 10
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);
		}