예제 #1
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;
		}
        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;
                }
            }
        }
예제 #3
0
		static BindableProperty GetBindableProperty(Type elementType, string localName, IXmlLineInfo lineInfo,
			bool throwOnError = false)
		{
			var bindableFieldInfo =
				elementType.GetFields().FirstOrDefault(fi => fi.Name == localName + "Property" && fi.IsStatic && fi.IsPublic);

			Exception exception = null;
			if (exception == null && bindableFieldInfo == null)
			{
				exception =
					new XamlParseException(
						string.Format("BindableProperty {0} not found on {1}", localName + "Property", elementType.Name), lineInfo);
			}

			if (exception == null)
				return bindableFieldInfo.GetValue(null) as BindableProperty;
			if (throwOnError)
				throw exception;
			return null;
		}
예제 #4
0
        public static Type GetElementType(XmlType xmlType, IXmlLineInfo xmlInfo, Assembly currentAssembly,
                                          out XamlParseException exception)
        {
            if (s_xmlnsDefinitions == null)
            {
                GatherXmlnsDefinitionAttributes();
            }

            var namespaceURI  = xmlType.NamespaceUri;
            var elementName   = xmlType.Name;
            var typeArguments = xmlType.TypeArguments;

            exception = null;

            var lookupAssemblies = new List <XmlnsDefinitionAttribute>();
            var lookupNames      = new List <string>();

            foreach (var xmlnsDef in s_xmlnsDefinitions)
            {
                if (xmlnsDef.XmlNamespace != namespaceURI)
                {
                    continue;
                }
                lookupAssemblies.Add(xmlnsDef);
            }

            if (lookupAssemblies.Count == 0)
            {
                string ns, asmstring, _;
                XmlnsHelper.ParseXmlns(namespaceURI, out _, out ns, out asmstring, out _);
                lookupAssemblies.Add(new XmlnsDefinitionAttribute(namespaceURI, ns)
                {
                    AssemblyName = asmstring ?? currentAssembly.FullName
                });
            }

            lookupNames.Add(elementName);
            lookupNames.Add(elementName + "Extension");

            for (var i = 0; i < lookupNames.Count; i++)
            {
                var name = lookupNames[i];
                if (name.Contains(":"))
                {
                    name = name.Substring(name.LastIndexOf(':') + 1);
                }
                if (typeArguments != null)
                {
                    name += "`" + typeArguments.Count;                     //this will return an open generic Type
                }
                lookupNames[i] = name;
            }

            Type type = null;

            foreach (var asm in lookupAssemblies)
            {
                foreach (var name in lookupNames)
                {
                    if ((type = Type.GetType($"{asm.ClrNamespace}.{name}, {asm.AssemblyName}")) != null)
                    {
                        break;
                    }
                }
                if (type != null)
                {
                    break;
                }
            }

            if (type != null && typeArguments != null)
            {
                XamlParseException innerexception = null;
                var args = typeArguments.Select(delegate(XmlType xmltype)
                {
                    XamlParseException xpe;
                    var t = GetElementType(xmltype, xmlInfo, currentAssembly, out xpe);
                    if (xpe != null)
                    {
                        innerexception = xpe;
                        return(null);
                    }
                    return(t);
                }).ToArray();
                if (innerexception != null)
                {
                    exception = innerexception;
                    return(null);
                }
                type = type.MakeGenericType(args);
            }

            if (type == null)
            {
                exception = new XamlParseException($"Type {elementName} not found in xmlns {namespaceURI}", xmlInfo);
            }

            return(type);
        }
        static bool TrySetValue(object element, BindableProperty property, bool attached, object value, IXmlLineInfo lineInfo, XamlServiceProvider serviceProvider, out Exception exception)
        {
            exception = null;

            var elementType          = element.GetType();
            var bindable             = element as BindableObject;
            var nativeBindingService = DependencyService.Get <INativeBindingService>();

            if (property == null)
            {
                return(false);
            }

            if (serviceProvider != null && serviceProvider.IProvideValueTarget != null)
            {
                ((XamlValueTargetProvider)serviceProvider.IProvideValueTarget).TargetProperty = property;
            }

            Func <MemberInfo> minforetriever;

            if (attached)
            {
                minforetriever = () =>
                {
                    try {
                        return(property.DeclaringType.GetRuntimeMethod("Get" + property.PropertyName, new[] { typeof(BindableObject) }));
                    } catch (AmbiguousMatchException e) {
                        throw new XamlParseException($"Multiple methods with name '{property.DeclaringType}.Get{property.PropertyName}' found.", lineInfo, innerException: e);
                    }
                }
            }
            ;
            else
            {
                minforetriever = () =>
                {
                    try {
                        return(property.DeclaringType.GetRuntimeProperty(property.PropertyName));
                    } catch (AmbiguousMatchException e) {
                        throw new XamlParseException($"Multiple properties with name '{property.DeclaringType}.{property.PropertyName}' found.", lineInfo, innerException: e);
                    }
                }
            };
            var convertedValue = value.ConvertTo(property.ReturnType, minforetriever, serviceProvider);

            if (bindable != null)
            {
                //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)))
                {
                    bindable.SetValue(property, convertedValue);
                    return(true);
                }

                // This might be a collection; see if we can add to it
                return(TryAddValue(bindable, property, value, serviceProvider));
            }

            if (nativeBindingService != null && nativeBindingService.TrySetValue(element, property, convertedValue))
            {
                return(true);
            }

            exception = new XamlParseException($"{elementType.Name} is not a BindableObject or does not support setting native BindableProperties", lineInfo);
            return(false);
        }
예제 #6
0
        public static Type GetElementType(XmlType xmlType, IXmlLineInfo xmlInfo, Assembly currentAssembly,
                                          out XamlParseException exception)
        {
#if NETSTANDARD2_0
            bool hasRetriedNsSearch = false;
#endif
            IList <XamlLoader.FallbackTypeInfo> potentialTypes;

#if NETSTANDARD2_0
retry:
#endif
            if (s_xmlnsDefinitions == null)
            {
                GatherXmlnsDefinitionAttributes();
            }

            Type type = xmlType.GetTypeReference(
                s_xmlnsDefinitions,
                currentAssembly?.FullName,
                (typeInfo) =>
                Type.GetType($"{typeInfo.ClrNamespace}.{typeInfo.TypeName}, {typeInfo.AssemblyName}"),
                out potentialTypes);

            var typeArguments = xmlType.TypeArguments;
            exception = null;

            if (type != null && typeArguments != null)
            {
                XamlParseException innerexception = null;
                var args = typeArguments.Select(delegate(XmlType xmltype) {
                    var t = GetElementType(xmltype, xmlInfo, currentAssembly, out XamlParseException xpe);
                    if (xpe != null)
                    {
                        innerexception = xpe;
                        return(null);
                    }
                    return(t);
                }).ToArray();
                if (innerexception != null)
                {
                    exception = innerexception;
                    return(null);
                }
                type = type.MakeGenericType(args);
            }

#if NETSTANDARD2_0
            if (type == null)
            {
                // This covers the scenario where the AppDomain's loaded
                // assemblies might have changed since this method was first
                // called. This occurred during unit test runs and could
                // conceivably occur in the field.
                if (!hasRetriedNsSearch)
                {
                    hasRetriedNsSearch = true;
                    s_xmlnsDefinitions = null;
                    goto retry;
                }
            }
#endif

            if (XamlLoader.FallbackTypeResolver != null)
            {
                type = XamlLoader.FallbackTypeResolver(potentialTypes, type);
            }

            if (type == null)
            {
                exception = new XamlParseException($"Type {xmlType.Name} not found in xmlns {xmlType.NamespaceUri}", xmlInfo);
            }

            return(type);
        }
예제 #7
0
        internal static object ConvertTo(this object value, Type toType, Func <object> getConverter,
                                         IServiceProvider serviceProvider, out Exception exception)
        {
            exception = null;
            if (value == null)
            {
                return(null);
            }

            if (value is string str)
            {
                //If there's a [TypeConverter], use it
                object converter;
                try
                {                 //minforetriver can fail
                    converter = getConverter?.Invoke();
                }
                catch (Exception e)
                {
                    exception = e;
                    return(null);
                }
                try
                {
                    if (converter is IExtendedTypeConverter xfExtendedTypeConverter)
                    {
                        return(xfExtendedTypeConverter.ConvertFromInvariantString(str, serviceProvider));
                    }
                    if (converter is TypeConverter xfTypeConverter)
                    {
                        return(xfTypeConverter.ConvertFromInvariantString(str));
                    }
                }
                catch (Exception e)
                {
                    exception = e as XamlParseException ?? new XamlParseException($"Type converter failed: {e.Message}", serviceProvider, e);
                    return(null);
                }
                var converterType = converter?.GetType();
                if (converterType != null)
                {
                    var convertFromStringInvariant = converterType.GetRuntimeMethod("ConvertFromInvariantString",
                                                                                    new[] { typeof(string) });
                    if (convertFromStringInvariant != null)
                    {
                        try
                        {
                            return(convertFromStringInvariant.Invoke(converter, new object[] { str }));
                        }
                        catch (Exception e)
                        {
                            exception = new XamlParseException("Type conversion failed", serviceProvider, e);
                            return(null);
                        }
                    }
                }
                var ignoreCase = (serviceProvider?.GetService(typeof(IConverterOptions)) as IConverterOptions)?.IgnoreCase ?? false;

                //If the type is nullable, as the value is not null, it's safe to assume we want the built-in conversion
                if (toType.GetTypeInfo().IsGenericType&& toType.GetGenericTypeDefinition() == typeof(Nullable <>))
                {
                    toType = Nullable.GetUnderlyingType(toType);
                }

                //Obvious Built-in conversions
                try
                {
                    if (toType.GetTypeInfo().IsEnum)
                    {
                        return(Enum.Parse(toType, str, ignoreCase));
                    }
                    if (toType == typeof(SByte))
                    {
                        return(SByte.Parse(str, CultureInfo.InvariantCulture));
                    }
                    if (toType == typeof(Int16))
                    {
                        return(Int16.Parse(str, CultureInfo.InvariantCulture));
                    }
                    if (toType == typeof(Int32))
                    {
                        return(Int32.Parse(str, CultureInfo.InvariantCulture));
                    }
                    if (toType == typeof(Int64))
                    {
                        return(Int64.Parse(str, CultureInfo.InvariantCulture));
                    }
                    if (toType == typeof(Byte))
                    {
                        return(Byte.Parse(str, CultureInfo.InvariantCulture));
                    }
                    if (toType == typeof(UInt16))
                    {
                        return(UInt16.Parse(str, CultureInfo.InvariantCulture));
                    }
                    if (toType == typeof(UInt32))
                    {
                        return(UInt32.Parse(str, CultureInfo.InvariantCulture));
                    }
                    if (toType == typeof(UInt64))
                    {
                        return(UInt64.Parse(str, CultureInfo.InvariantCulture));
                    }
                    if (toType == typeof(Single))
                    {
                        return(Single.Parse(str, CultureInfo.InvariantCulture));
                    }
                    if (toType == typeof(Double))
                    {
                        return(Double.Parse(str, CultureInfo.InvariantCulture));
                    }
                    if (toType == typeof(Boolean))
                    {
                        return(Boolean.Parse(str));
                    }
                    if (toType == typeof(TimeSpan))
                    {
                        return(TimeSpan.Parse(str, CultureInfo.InvariantCulture));
                    }
                    if (toType == typeof(DateTime))
                    {
                        return(DateTime.Parse(str, CultureInfo.InvariantCulture));
                    }
                    if (toType == typeof(Char))
                    {
                        Char.TryParse(str, out var c);
                        return(c);
                    }
                    if (toType == typeof(String) && str.StartsWith("{}", StringComparison.Ordinal))
                    {
                        return(str.Substring(2));
                    }
                    if (toType == typeof(String))
                    {
                        return(value);
                    }
                    if (toType == typeof(Decimal))
                    {
                        return(Decimal.Parse(str, CultureInfo.InvariantCulture));
                    }
                }
                catch (FormatException fe)
                {
                    exception = fe;
                    return(null);
                }
            }

            //if the value is not assignable and there's an implicit conversion, convert
            if (value != null && !toType.IsAssignableFrom(value.GetType()))
            {
                var opImplicit = value.GetType().GetImplicitConversionOperator(fromType: value.GetType(), toType: toType)
                                 ?? toType.GetImplicitConversionOperator(fromType: value.GetType(), toType: toType);

                if (opImplicit != null)
                {
                    value = opImplicit.Invoke(null, new[] { value });
                    return(value);
                }
            }

            var nativeValueConverterService = DependencyService.Get <INativeValueConverterService>();

            object nativeValue = null;

            if (nativeValueConverterService != null && nativeValueConverterService.ConvertTo(value, toType, out nativeValue))
            {
                return(nativeValue);
            }

            return(value);
        }
예제 #8
0
        public static Type GetElementType(XmlType xmlType, IXmlLineInfo xmlInfo, Assembly currentAssembly,
                                          out XamlParseException exception)
        {
            var namespaceURI  = xmlType.NamespaceUri;
            var elementName   = xmlType.Name;
            var typeArguments = xmlType.TypeArguments;

            exception = null;

            var lookupAssemblies = new List <Tuple <string, string> >();          //namespace, assemblyqualifiednamed
            var lookupNames      = new List <string>();

            if (!XmlnsHelper.IsCustom(namespaceURI))
            {
                lookupAssemblies.Add(new Tuple <string, string>("Xamarin.Forms", typeof(View).GetTypeInfo().Assembly.FullName));
                lookupAssemblies.Add(new Tuple <string, string>("Xamarin.Forms.Xaml", typeof(XamlLoader).GetTypeInfo().Assembly.FullName));
            }
            else if (namespaceURI == "http://schemas.microsoft.com/winfx/2009/xaml" ||
                     namespaceURI == "http://schemas.microsoft.com/winfx/2006/xaml")
            {
                lookupAssemblies.Add(new Tuple <string, string>("Xamarin.Forms.Xaml", typeof(XamlLoader).GetTypeInfo().Assembly.FullName));
                lookupAssemblies.Add(new Tuple <string, string>("System", typeof(object).GetTypeInfo().Assembly.FullName));              //mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
                lookupAssemblies.Add(new Tuple <string, string>("System", typeof(Uri).GetTypeInfo().Assembly.FullName));                 //System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
            }
            else
            {
                string ns, asmstring, _;
                XmlnsHelper.ParseXmlns(namespaceURI, out _, out ns, out asmstring, out _);
                lookupAssemblies.Add(new Tuple <string, string>(ns, asmstring ?? currentAssembly.FullName));
            }

            lookupNames.Add(elementName);
            if (namespaceURI == "http://schemas.microsoft.com/winfx/2009/xaml")
            {
                lookupNames.Add(elementName + "Extension");
            }
            for (var i = 0; i < lookupNames.Count; i++)
            {
                var name = lookupNames[i];
                if (name.Contains(":"))
                {
                    name = name.Substring(name.LastIndexOf(':') + 1);
                }
                if (typeArguments != null)
                {
                    name += "`" + typeArguments.Count;                     //this will return an open generic Type
                }
                lookupNames[i] = name;
            }

            Type type = null;

            foreach (var asm in lookupAssemblies)
            {
                foreach (var name in lookupNames)
                {
                    if ((type = Type.GetType($"{asm.Item1}.{name}, {asm.Item2}")) != null)
                    {
                        break;
                    }
                }
                if (type != null)
                {
                    break;
                }
            }

            if (type != null && typeArguments != null)
            {
                XamlParseException innerexception = null;
                var args = typeArguments.Select(delegate(XmlType xmltype)
                {
                    XamlParseException xpe;
                    var t = GetElementType(xmltype, xmlInfo, currentAssembly, out xpe);
                    if (xpe != null)
                    {
                        innerexception = xpe;
                        return(null);
                    }
                    return(t);
                }).ToArray();
                if (innerexception != null)
                {
                    exception = innerexception;
                    return(null);
                }
                type = type.MakeGenericType(args);
            }

            if (type == null)
            {
                exception = new XamlParseException($"Type {elementName} not found in xmlns {namespaceURI}", xmlInfo);
            }

            return(type);
        }
예제 #9
0
        public static Type GetElementType(XmlType xmlType, IXmlLineInfo xmlInfo, Assembly currentAssembly,
                                          out XamlParseException exception)
        {
            bool hasRetriedNsSearch = false;

retry:
            if (s_xmlnsDefinitions == null)
            {
                GatherXmlnsDefinitionAttributes();
            }

            var namespaceURI  = xmlType.NamespaceUri;
            var elementName   = xmlType.Name;
            var typeArguments = xmlType.TypeArguments;

            exception = null;

            var lookupAssemblies = new List <XmlnsDefinitionAttribute>();
            var lookupNames      = new List <string>();

            foreach (var xmlnsDef in s_xmlnsDefinitions)
            {
                if (xmlnsDef.XmlNamespace != namespaceURI)
                {
                    continue;
                }
                lookupAssemblies.Add(xmlnsDef);
            }

            if (lookupAssemblies.Count == 0)
            {
                string ns, asmstring, _;
                XmlnsHelper.ParseXmlns(namespaceURI, out _, out ns, out asmstring, out _);
                lookupAssemblies.Add(new XmlnsDefinitionAttribute(namespaceURI, ns)
                {
                    AssemblyName = asmstring ?? currentAssembly.FullName
                });
            }

            lookupNames.Add(elementName);
            lookupNames.Add(elementName + "Extension");

            for (var i = 0; i < lookupNames.Count; i++)
            {
                var name = lookupNames[i];
                if (name.Contains(":"))
                {
                    name = name.Substring(name.LastIndexOf(':') + 1);
                }
                if (typeArguments != null)
                {
                    name += "`" + typeArguments.Count;                     //this will return an open generic Type
                }
                lookupNames[i] = name;
            }

            Type type = null;

            foreach (var asm in lookupAssemblies)
            {
                foreach (var name in lookupNames)
                {
                    if ((type = Type.GetType($"{asm.ClrNamespace}.{name}, {asm.AssemblyName}")) != null)
                    {
                        break;
                    }
                }
                if (type != null)
                {
                    break;
                }
            }

            if (type != null && typeArguments != null)
            {
                XamlParseException innerexception = null;
                var args = typeArguments.Select(delegate(XmlType xmltype)
                {
                    XamlParseException xpe;
                    var t = GetElementType(xmltype, xmlInfo, currentAssembly, out xpe);
                    if (xpe != null)
                    {
                        innerexception = xpe;
                        return(null);
                    }
                    return(t);
                }).ToArray();
                if (innerexception != null)
                {
                    exception = innerexception;
                    return(null);
                }
                type = type.MakeGenericType(args);
            }

            if (type == null)
            {
#if NETSTANDARD2_0
                // This covers the scenario where the AppDomain's loaded
                // assemblies might have changed since this method was first
                // called. This occurred during unit test runs and could
                // conceivably occur in the field.
                if (!hasRetriedNsSearch)
                {
                    hasRetriedNsSearch = true;
                    s_xmlnsDefinitions = null;
                    goto retry;
                }
#endif
                exception = new XamlParseException($"Type {elementName} not found in xmlns {namespaceURI}. Ensure third party control libraries are referenced in the code of your project and not just in XAML.  Third party control authors must also apply the \"Preserve\" attribute on their assemblies or any control classes.", xmlInfo);
            }

            return(type);
        }
예제 #10
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(addMethod.GetParameters()[0].ParameterType, (Func <TypeConverter>)null, serviceProvider) });
                    return;
                }
            }

            if (context.DoNotThrowOnExceptions)
            {
                System.Diagnostics.Debug.WriteLine(exception.Message);
            }
            else
            {
                throw exception;
            }
        }
예제 #11
0
		public static Type GetElementType(XmlType xmlType, IXmlLineInfo xmlInfo, Assembly currentAssembly,
			out XamlParseException exception)
		{
			var namespaceURI = xmlType.NamespaceUri;
			var elementName = xmlType.Name;
			var typeArguments = xmlType.TypeArguments;
			exception = null;

			List<Tuple<string, Assembly>> lookupAssemblies = new List<Tuple<string, Assembly>>();
			List<string> lookupNames = new List<string>();

			if (!XmlnsHelper.IsCustom(namespaceURI))
			{
				lookupAssemblies.Add(new Tuple<string, Assembly>("Xamarin.Forms", typeof (View).GetTypeInfo().Assembly));
				lookupAssemblies.Add(new Tuple<string, Assembly>("Xamarin.Forms.Xaml", typeof (XamlLoader).GetTypeInfo().Assembly));
			}
			else if (namespaceURI == "http://schemas.microsoft.com/winfx/2009/xaml" ||
			         namespaceURI == "http://schemas.microsoft.com/winfx/2006/xaml")
			{
				lookupAssemblies.Add(new Tuple<string, Assembly>("Xamarin.Forms.Xaml", typeof (XamlLoader).GetTypeInfo().Assembly));
				lookupAssemblies.Add(new Tuple<string, Assembly>("System", typeof (object).GetTypeInfo().Assembly));
				lookupAssemblies.Add(new Tuple<string, Assembly>("System", typeof (Uri).GetTypeInfo().Assembly)); //System.dll
			}
			else
			{
				string ns;
				string typename;
				string asmstring;
				Assembly asm;

				XmlnsHelper.ParseXmlns(namespaceURI, out typename, out ns, out asmstring);
				asm = asmstring == null ? currentAssembly : Assembly.Load(new AssemblyName(asmstring));
				lookupAssemblies.Add(new Tuple<string, Assembly>(ns, asm));
			}

			lookupNames.Add(elementName);
			if (namespaceURI == "http://schemas.microsoft.com/winfx/2009/xaml")
				lookupNames.Add(elementName + "Extension");
			for (var i = 0; i < lookupNames.Count; i++)
			{
				var name = lookupNames[i];
				if (name.Contains(":"))
					name = name.Substring(name.LastIndexOf(':') + 1);
				if (typeArguments != null)
					name += "`" + typeArguments.Count; //this will return an open generic Type
				lookupNames[i] = name;
			}

			Type type = null;
			foreach (var asm in lookupAssemblies)
			{
				if (type != null)
					break;
				foreach (var name in lookupNames)
				{
					if (type != null)
						break;
					type = asm.Item2.GetType(asm.Item1 + "." + name);
				}
			}

			if (type != null && typeArguments != null)
			{
				XamlParseException innerexception = null;
				var args = typeArguments.Select(delegate(XmlType xmltype)
				{
					XamlParseException xpe;
					var t = GetElementType(xmltype, xmlInfo, currentAssembly, out xpe);
					if (xpe != null)
					{
						innerexception = xpe;
						return null;
					}
					return t;
				}).ToArray();
				if (innerexception != null)
				{
					exception = innerexception;
					return null;
				}
				type = type.MakeGenericType(args);
			}

			if (type == null)
			{
				exception = new XamlParseException(string.Format("Type {0} not found in xmlns {1}", elementName, namespaceURI),
					xmlInfo);
				return null;
			}

			return type;
		}
예제 #12
0
            public INode Parse(string match, ref string remaining, IServiceProvider serviceProvider)
            {
                var nsResolver = serviceProvider.GetService(typeof(IXmlNamespaceResolver)) as IXmlNamespaceResolver;

                if (nsResolver == null)
                {
                    throw new ArgumentException();
                }
                IXmlLineInfo xmlLineInfo         = null;
                var          xmlLineInfoProvider = serviceProvider.GetService(typeof(IXmlLineInfoProvider)) as IXmlLineInfoProvider;

                if (xmlLineInfoProvider != null)
                {
                    xmlLineInfo = xmlLineInfoProvider.XmlLineInfo;
                }

                var split = match.Split(':');

                if (split.Length > 2)
                {
                    throw new ArgumentException();
                }

                string prefix;                 //, name;

                if (split.Length == 2)
                {
                    prefix = split[0];
                    //					name = split [1];
                }
                else
                {
                    prefix = "";
                    //					name = split [0];
                }

                Type type;
                var  typeResolver = serviceProvider.GetService(typeof(IXamlTypeResolver)) as IXamlTypeResolver;

                if (typeResolver == null)
                {
                    type = null;
                }
                else
                {
                    //The order of lookup is to look for the Extension-suffixed class name first and then look for the class name without the Extension suffix.
                    if (!typeResolver.TryResolve(match + "Extension", out type) && !typeResolver.TryResolve(match, out type))
                    {
                        var ex = new XamlParseException($"MarkupExtension not found for {match}", serviceProvider);
                        if (ExceptionHandler != null)
                        {
                            ExceptionHandler(ex);
                            return(null);
                        }
                        throw ex;
                    }
                }

                var namespaceuri = nsResolver.LookupNamespace(prefix) ?? "";
                var xmltype      = new XmlType(namespaceuri, type.Name, null);

                if (type == null)
                {
                    throw new NotSupportedException();
                }

                node = xmlLineInfo == null
                                        ? new ElementNode(xmltype, null, nsResolver)
                                        : new ElementNode(xmltype, null, nsResolver, xmlLineInfo.LineNumber, xmlLineInfo.LinePosition);

                if (remaining.StartsWith("}", StringComparison.Ordinal))
                {
                    remaining = remaining.Substring(1);
                    return(node);
                }

                char   next;
                string piece;

                while ((piece = GetNextPiece(ref remaining, out next)) != null)
                {
                    HandleProperty(piece, serviceProvider, ref remaining, next != '=');
                }

                return(node);
            }