Ejemplo n.º 1
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] });
			}
		}
Ejemplo n.º 2
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);
		}
Ejemplo n.º 3
0
		public static void SetPropertyValue(object xamlelement, XmlName propertyName, object value, object rootElement,
			INode node, HydratationContext context, IXmlLineInfo lineInfo)
		{
			var elementType = xamlelement.GetType();
			var localname = propertyName.LocalName;

			var serviceProvider = new XamlServiceProvider(node, context);

			//If it's an attached BP, update elementType and propertyName
			var attached = GetRealNameAndType(ref elementType, propertyName.NamespaceURI, ref localname, context, lineInfo);

			//If the target is an event, connect
			var eventInfo = elementType.GetRuntimeEvent(localname);
			if (eventInfo != null && value is string)
			{
				var methodInfo = rootElement.GetType().GetRuntimeMethods().FirstOrDefault(mi => mi.Name == (string)value);
				if (methodInfo == null) {
					var xpe = new XamlParseException (string.Format ("No method {0} found on type {1}", value, rootElement.GetType ()), lineInfo);
					if (context.DoNotThrowOnExceptions) {
						System.Diagnostics.Debug.WriteLine (xpe.Message);
						return;
					} else
						throw xpe;
				}
				try
				{
					eventInfo.AddEventHandler(xamlelement, methodInfo.CreateDelegate(eventInfo.EventHandlerType, rootElement));
				}
				catch (ArgumentException)
				{
					var xpe = new XamlParseException (string.Format ("Method {0} does not have the correct signature", value), lineInfo);
					if (context.DoNotThrowOnExceptions)
						System.Diagnostics.Debug.WriteLine (xpe.Message);
					else
						throw xpe;
				}

				return;
			}

			var property = GetBindableProperty(elementType, localname, lineInfo, false);

			//If Value is DynamicResource and it's a BP, SetDynamicResource
			if (value is DynamicResource && property != null)
			{
				if (!(xamlelement.GetType()).GetTypeInfo().IsSubclassOf(typeof (BindableObject)))
					throw new XamlParseException(string.Format("{0} is not a BindableObject", xamlelement.GetType().Name), lineInfo);
				((BindableObject)xamlelement).SetDynamicResource(property, ((DynamicResource)value).Key);
				return;
			}

			//If value is BindingBase, and target is a BindableProperty, SetBinding
			if (value is BindingBase && property != null)
			{
				if (!(xamlelement.GetType()).GetTypeInfo().IsSubclassOf(typeof (BindableObject)))
					throw new XamlParseException(string.Format("{0} is not a BindableObject", xamlelement.GetType().Name), lineInfo);

				((BindableObject)xamlelement).SetBinding(property, value as BindingBase);
				return;
			}

			//If it's a BindableProberty, SetValue
			if (property != null)
			{
				if (!(xamlelement.GetType()).GetTypeInfo().IsSubclassOf(typeof (BindableObject)))
					throw new XamlParseException(string.Format("{0} is not a BindableObject", xamlelement.GetType().Name), lineInfo);
				Func<MemberInfo> minforetriever;
				if (attached)
					minforetriever = () => elementType.GetRuntimeMethod("Get" + localname, new[] { typeof (BindableObject) });
				else
					minforetriever = () => elementType.GetRuntimeProperty(localname);

				var convertedValue = value.ConvertTo(property.ReturnType, minforetriever, serviceProvider);

				//SetValue doesn't throw on mismatching type, so check before to get a chance to try the property setting or the collection adding
				var nullable = property.ReturnTypeInfo.IsGenericType &&
				               property.ReturnTypeInfo.GetGenericTypeDefinition() == typeof (Nullable<>);
				if ((convertedValue == null && (!property.ReturnTypeInfo.IsValueType || nullable)) ||
				    (property.ReturnType.IsInstanceOfType(convertedValue)))
				{
					((BindableObject)xamlelement).SetValue(property, convertedValue);
					return;
				}
			}

			var exception = new XamlParseException(
				String.Format("No Property of name {0} found", propertyName.LocalName), lineInfo);

			//If we can assign that value to a normal property, let's do it
			var propertyInfo = elementType.GetRuntimeProperties().FirstOrDefault(p => p.Name == localname);
			MethodInfo setter;
			if (propertyInfo != null && propertyInfo.CanWrite && (setter = propertyInfo.SetMethod) != null)
			{
				object convertedValue = value.ConvertTo(propertyInfo.PropertyType, () => propertyInfo, serviceProvider);
				if (convertedValue == null || propertyInfo.PropertyType.IsInstanceOfType(convertedValue))
				{
					try
					{
						setter.Invoke(xamlelement, new[] { convertedValue });
						return;
					}
					catch (ArgumentException)
					{
					}
				}
				else
				{
					exception = new XamlParseException(
						String.Format("Cannot assign property \"{0}\": type mismatch between \"{1}\" and \"{2}\"", propertyName.LocalName,
							value.GetType(), propertyInfo.PropertyType), lineInfo);
				}
			}

			//If it's an already initialized property, add to it
			MethodInfo getter;
			if (propertyInfo != null && propertyInfo.CanRead && (getter = propertyInfo.GetMethod) != null)
			{
				IEnumerable collection;
				MethodInfo addMethod;
				if ((collection = getter.Invoke(xamlelement, new object[] { }) as IEnumerable) != null
				    &&
				    (addMethod =
					    collection.GetType().GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1)) !=
				    null)
				{
					addMethod.Invoke(collection,
						new[] { value.ConvertTo(propertyInfo.PropertyType, (Func<TypeConverter>)null, serviceProvider) });
					return;
				}
			}

			if (context.DoNotThrowOnExceptions)
				System.Diagnostics.Debug.WriteLine (exception.Message);
			else
				throw exception;
		}
Ejemplo n.º 4
0
		public object[] CreateArgumentsArray(IElementNode enode, ConstructorInfo ctorInfo)
		{
			var n = ctorInfo.GetParameters().Length;
			var array = new object[n];
			for (var i = 0; i < n; i++)
			{
				var parameter = ctorInfo.GetParameters()[i];
				var propname =
					parameter.CustomAttributes.First(attr => attr.AttributeType == typeof (ParameterAttribute))
						.ConstructorArguments.First()
						.Value as string;
				var name = new XmlName("", propname);
				INode node;
				if (!enode.Properties.TryGetValue(name, out node))
				{
					throw new XamlParseException(
						String.Format("The Property {0} is required to create a {1} object.", propname, ctorInfo.DeclaringType.FullName),
						enode as IXmlLineInfo);
				}
				if (!enode.SkipProperties.Contains(name))
					enode.SkipProperties.Add(name);
				var value = Context.Values[node];
				var serviceProvider = new XamlServiceProvider(enode, Context);
				var convertedValue = value.ConvertTo(parameter.ParameterType, () => parameter, serviceProvider);
				array[i] = convertedValue;
			}

			return array;
		}