Пример #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;
		}
Пример #2
0
 public bool IsResourceDictionary(ElementNode node) => false;
Пример #3
0
		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] });
			}
		}
Пример #4
0
 public void Visit(ElementNode node, INode parentNode)
 => _scopes[node] = node.Namescope = (parentNode == null || IsDataTemplate(node, parentNode) || IsStyle(node, parentNode) || IsVisualStateGroupList(node))
                                                            ? new NameScope()
                                                            : _scopes[parentNode];
Пример #5
0
		public void Visit(ElementNode node, INode parentNode)
		{
		}
Пример #6
0
		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));
		}
Пример #7
0
 public void Visit(ElementNode node, INode parentNode)
 {
 }
Пример #8
0
        public void Visit(ElementNode node, INode parentNode)
        {
            object value = null;

            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($"The Property {ctorargname} is required to create a {type.FullName} object.", 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 markup = value as IMarkupExtension;

            if (markup != null && (value is TypeExtension || value is StaticExtension || value is ArrayExtension))
            {
                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 = markup.ProvideValue(serviceProvider);

                INode xKey;
                if (!node.Properties.TryGetValue(XmlName.xKey, out xKey))
                {
                    xKey = null;
                }

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

                if (xKey != null)
                {
                    node.Properties.Add(XmlName.xKey, xKey);
                }

                Values[node] = value;
            }

            if (value is BindableObject)
            {
                NameScope.SetNameScope(value as BindableObject, node.Namescope);
            }
        }
Пример #9
0
 static bool IsVisualStateGroupList(ElementNode node)
 {
     return(node != null && node.XmlType.Name == "VisualStateGroup" && node.Parent is IListNode);
 }
Пример #10
0
 static bool IsVisualStateGroupList(ElementNode node) => node?.XmlType.Name == "VisualStateGroup" && node?.Parent is IListNode;
Пример #11
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);
		}
Пример #12
0
 public bool IsResourceDictionary(ElementNode node) => Context.Types.TryGetValue(node, out var type) && typeof(ResourceDictionary).IsAssignableFrom(type);
Пример #13
0
        public void Visit(ElementNode node, INode parentNode)
        {
            XmlName propertyName;

            if (TryGetPropertyName(node, parentNode, out propertyName) && propertyName == XmlName._CreateContent)
            {
                var s0 = Values[parentNode];
                if (s0 is ElementTemplate)
                {
                    SetTemplate(s0 as ElementTemplate, node);
                    return;
                }
            }

            var parentElement = parentNode as IElementNode;

            propertyName = XmlName.Empty;

            //Simplify ListNodes with single elements
            var pList = parentNode as ListNode;

            if (pList != null && pList.CollectionItems.Count == 1)
            {
                propertyName  = pList.XmlName;
                parentNode    = parentNode.Parent;
                parentElement = parentNode as IElementNode;
            }

            var value = Values[node];

            if (propertyName != XmlName.Empty || TryGetPropertyName(node, parentNode, out propertyName))
            {
                if (Skips.Contains(propertyName))
                {
                    return;
                }
                if (parentElement.SkipProperties.Contains(propertyName))
                {
                    return;
                }

                var source = Values[parentNode];
                ProvideValue(ref value, node, source, propertyName);
                SetPropertyValue(source, propertyName, value, Context.RootElement, node, Context, node);
            }
            else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode)
            {
                var source = Values[parentNode];
                ProvideValue(ref value, node, source, XmlName.Empty);
                string contentProperty;

                // Implicit Style Resource in a ResourceDictionary
                if (typeof(ResourceDictionary).IsAssignableFrom(Context.Types[parentElement]) && value is Style &&
                    !node.Properties.ContainsKey(XmlName.xKey))
                {
                    ((ResourceDictionary)source).Add(value as Style);
                }
                // Resource without a x:Key in a ResourceDictionary
                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);
                }
                // Resource in a ResourceDictionary
                else if (typeof(ResourceDictionary).IsAssignableFrom(Context.Types[parentElement]) && node.Properties.ContainsKey(XmlName.xKey))
                {
                    ((ResourceDictionary)source).Add((string)(((ValueNode)node.Properties[XmlName.xKey]).Value), value);
                }
                // Collection element, implicit content, or implicit collection element.
                else if (typeof(IEnumerable).IsAssignableFrom(Context.Types[parentElement]) && Context.Types[parentElement].GetRuntimeMethods().Any(mi => mi.Name == "Add" && mi.GetParameters().Length == 1))
                {
                    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;
                    }

                    SetPropertyValue(source, name, value, Context.RootElement, node, Context, node);
                }
                else
                {
                    throw new XamlParseException($"Can not set the content of {((IElementNode)parentNode).XmlType.Name} as it doesn't have a ContentPropertyAttribute", node);
                }
            }
            else if (IsCollectionItem(node, parentNode) && parentNode is ListNode)
            {
                var source = Values[parentNode.Parent];
                ProvideValue(ref value, node, source, XmlName.Empty);

                var parentList = (ListNode)parentNode;

                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(Format("Property {0} not found", localname), node);
                }
                MethodInfo getter;
                if (!propertyInfo.CanRead || (getter = propertyInfo.GetMethod) == null)
                {
                    throw new XamlParseException(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(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(Format("Value of {0} does not have a Add() method", localname), node);
                }

                addMethod.Invoke(collection, new[] { Values[node] });
            }
        }
Пример #14
0
 public void Visit(ElementNode node, INode parentNode)
 {
     action(node, parentNode);
 }
Пример #15
0
        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] });
            }
        }
Пример #16
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;
                    IList <KeyValuePair <string, string> > xmlns;

                    var attributes = ParseXamlAttributes(reader, out xmlns);
                    var prefixes   = PrefixesToIgnore(xmlns);

                    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);
                    (node.IgnorablePrefixes ?? (node.IgnorablePrefixes = new List <string>())).AddRange(prefixes);

                    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);
        }
Пример #17
0
        public void Visit(ElementNode node, INode parentNode)
        {
            XmlName propertyName;

            if (TryGetPropertyName(node, parentNode, out propertyName) && propertyName == XmlName._CreateContent)
            {
                var s0 = Values[parentNode];
                if (s0 is ElementTemplate)
                {
                    SetTemplate(s0 as ElementTemplate, node);
                    return;
                }
            }

            var parentElement = parentNode as IElementNode;

            propertyName = XmlName.Empty;

            //Simplify ListNodes with single elements
            var pList = parentNode as ListNode;

            if (pList != null && pList.CollectionItems.Count == 1)
            {
                propertyName  = pList.XmlName;
                parentNode    = parentNode.Parent;
                parentElement = parentNode as IElementNode;
            }

            var value = Values[node];

            if (propertyName != XmlName.Empty || TryGetPropertyName(node, parentNode, out propertyName))
            {
                if (Skips.Contains(propertyName))
                {
                    return;
                }
                if (parentElement.SkipProperties.Contains(propertyName))
                {
                    return;
                }

                var source = Values[parentNode];
                ProvideValue(ref value, node, source, propertyName);
                SetPropertyValue(source, propertyName, value, Context.RootElement, node, Context, node);
            }
            else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode)
            {
                var source = Values[parentNode];
                ProvideValue(ref value, node, source, XmlName.Empty);
                string    contentProperty;
                Exception xpe  = null;
                var       xKey = node.Properties.ContainsKey(XmlName.xKey) ? ((ValueNode)node.Properties[XmlName.xKey]).Value as string : null;

                //ResourceDictionary
                if (xpe == null && TryAddToResourceDictionary(source as ResourceDictionary, value, xKey, node, out xpe))
                {
                    return;
                }

                // Collection element, implicit content, or implicit collection element.
                if (xpe == null && typeof(IEnumerable).IsAssignableFrom(Context.Types[parentElement]) && Context.Types[parentElement].GetRuntimeMethods().Any(mi => mi.Name == "Add" && mi.GetParameters().Length == 1))
                {
                    var addMethod =
                        Context.Types[parentElement].GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1);

                    addMethod.Invoke(source, new[] { value });
                    return;
                }
                if (xpe == null && (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;
                    }

                    SetPropertyValue(source, name, value, Context.RootElement, node, Context, node);
                    return;
                }
                xpe = xpe ?? new XamlParseException($"Can not set the content of {((IElementNode)parentNode).XmlType.Name} as it doesn't have a ContentPropertyAttribute", node);
                if (Context.ExceptionHandler != null)
                {
                    Context.ExceptionHandler(xpe);
                }
                else
                {
                    throw xpe;
                }
            }
            else if (IsCollectionItem(node, parentNode) && parentNode is ListNode)
            {
                var source = Values[parentNode.Parent];
                ProvideValue(ref value, node, source, XmlName.Empty);
                var parentList = (ListNode)parentNode;
                if (Skips.Contains(parentList.XmlName))
                {
                    return;
                }
                Exception xpe  = null;
                var       xKey = node.Properties.ContainsKey(XmlName.xKey) ? ((ValueNode)node.Properties[XmlName.xKey]).Value as string : null;

                object _;
                var    collection = GetPropertyValue(source, parentList.XmlName, Context, parentList, out _) as IEnumerable;
                if (collection == null)
                {
                    xpe = new XamlParseException($"Property {parentList.XmlName.LocalName} is null or is not IEnumerable", node);
                }

                if (xpe == null && TryAddToResourceDictionary(collection as ResourceDictionary, value, xKey, node, out xpe))
                {
                    return;
                }

                MethodInfo addMethod;
                if (xpe == null && (addMethod = collection.GetType().GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1)) != null)
                {
                    addMethod.Invoke(collection, new[] { Values[node] });
                    return;
                }
                xpe = xpe ?? new XamlParseException($"Value of {parentList.XmlName.LocalName} does not have a Add() method", node);
                if (Context.ExceptionHandler != null)
                {
                    Context.ExceptionHandler(xpe);
                }
                else
                {
                    throw xpe;
                }
            }
        }
Пример #18
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);
		}
        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;

            //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);
                }
            }
        }
Пример #20
0
		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);
			}
		}
Пример #21
0
 public bool IsResourceDictionary(ElementNode node) => typeof(ResourceDictionary).IsAssignableFrom(Context.Types[node]);
Пример #22
0
		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);
				}
			}
		}
Пример #23
0
        public void Visit(ElementNode node, INode parentNode)
        {
            object value = null;

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

            if (xpe != null)
            {
                if (Context.ExceptionHandler != null)
                {
                    Context.ExceptionHandler(xpe);
                    return;
                }
                throw xpe;
            }
            Context.Types[node] = type;
            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 string 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($"The Property {ctorargname} is required to create a {type.FullName} object.", 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, out Exception exception);
                        if (exception != null)
                        {
                            if (Context.ExceptionHandler != null)
                            {
                                Context.ExceptionHandler(exception);
                                return;
                            }
                            throw exception;
                        }
                        if (converted != null && converted.GetType() == type)
                        {
                            value = converted;
                        }
                    }
                    if (value == null)
                    {
                        try
                        {
                            value = Activator.CreateInstance(type);
                        }
                        catch (Exception e) when(e is TargetInvocationException || e is MemberAccessException)
                        {
                            value = XamlLoader.InstantiationFailedCallback?.Invoke(new XamlLoader.CallbackTypeInfo {
                                XmlNamespace = node.XmlType.NamespaceUri, XmlTypeName = node.XmlType.Name
                            }, type, e) ?? throw e;
                        }
                    }
                }
                catch (TargetInvocationException e) when(e.InnerException is XamlParseException || e.InnerException is XmlException)
                {
                    throw e.InnerException;
                }
                catch (MissingMemberException mme)
                {
                    throw new XamlParseException(mme.Message, node, mme);
                }
            }

            Values[node] = value;

            if (value is IMarkupExtension markup && (value is TypeExtension || value is StaticExtension || value is ArrayExtension))
            {
                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);
                }

                try
                {
                    value = markup.ProvideValue(serviceProvider);
                }
                catch (Exception e)
                {
                    var xamlpe = e as XamlParseException ?? new XamlParseException("Markup extension failed", serviceProvider, e);
                    if (Context.ExceptionHandler != null)
                    {
                        Context.ExceptionHandler(xamlpe);
                    }
                    else
                    {
                        throw xamlpe;
                    }
                }
                if (!node.Properties.TryGetValue(XmlName.xKey, out INode xKey))
                {
                    xKey = null;
                }

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

                if (xKey != null)
                {
                    node.Properties.Add(XmlName.xKey, xKey);
                }

                Values[node] = value;
            }

            if (value is BindableObject bindableValue && node.NameScopeRef != (parentNode as IElementNode)?.NameScopeRef)
            {
                NameScope.SetNameScope(bindableValue, node.NameScopeRef.NameScope);
            }

            if (XamlLoader.ValueCreatedCallback != null)
            {
                var name = node.XmlType.Name;
                if (name.Contains(":"))
                {
                    name = name.Substring(name.LastIndexOf(':') + 1);
                }
                XamlLoader.ValueCreatedCallback(new XamlLoader.CallbackTypeInfo {
                    XmlNamespace = node.XmlType.NamespaceUri, XmlTypeName = name
                }, value);
            }

            var assemblyName = (Context.RootAssembly ?? Context.RootElement?.GetType().GetTypeInfo().Assembly)?.GetName().Name;

            if (assemblyName != null && value != null && !value.GetType().GetTypeInfo().IsValueType&& XamlFilePathAttribute.GetFilePathForObject(Context.RootElement) is string path)
            {
                Diagnostics.VisualDiagnostics.RegisterSourceInfo(value, new Uri($"{path};assembly={assemblyName}", UriKind.Relative), ((IXmlLineInfo)node).LineNumber, ((IXmlLineInfo)node).LinePosition);
            }
        }
Пример #24
0
		public void Visit(ElementNode node, INode parentNode)
		{
			action(node, parentNode);
		}
Пример #25
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);
		}