static bool TryAddToProperty(object element, XmlName propertyName, object value, string xKey, IXmlLineInfo lineInfo, XamlServiceProvider serviceProvider, HydrationContext context, out Exception exception) { exception = null; object targetProperty; var collection = GetPropertyValue(element, propertyName, context, lineInfo, out targetProperty) as IEnumerable; if (collection == null) { return(false); } if (exception == null && TryAddToResourceDictionary(collection as ResourceDictionary, value, xKey, lineInfo, out exception)) { return(true); } if (exception != null) { return(false); } var addMethod = collection.GetType().GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1); if (addMethod == null) { return(false); } if (serviceProvider != null && serviceProvider.IProvideValueTarget != null) { ((XamlValueTargetProvider)serviceProvider.IProvideValueTarget).TargetProperty = targetProperty; } addMethod.Invoke(collection, new [] { value.ConvertTo(addMethod.GetParameters() [0].ParameterType, (Func <TypeConverter>)null, serviceProvider) }); return(true); }
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 = () => property.DeclaringType.GetRuntimeMethod("Get" + property.PropertyName, new [] { typeof(BindableObject) }); } else { minforetriever = () => property.DeclaringType.GetRuntimeProperties().LastOrDefault(p => p.Name == property.PropertyName); } //minforetriever = () => property.DeclaringType.GetRuntimeProperty(property.PropertyName); 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); }
static bool TrySetProperty(object element, string localName, object value, IXmlLineInfo lineInfo, XamlServiceProvider serviceProvider, HydrationContext context, out Exception exception) { exception = null; var elementType = element.GetType(); var propertyInfo = elementType.GetRuntimeProperties().FirstOrDefault(p => p.Name == localName); MethodInfo setter; if (propertyInfo == null || !propertyInfo.CanWrite || (setter = propertyInfo.SetMethod) == null) { return(false); } if (!IsVisibleFrom(setter, context.RootElement)) { return(false); } if (serviceProvider != null && serviceProvider.IProvideValueTarget != null) { ((XamlValueTargetProvider)serviceProvider.IProvideValueTarget).TargetProperty = propertyInfo; } object convertedValue = value.ConvertTo(propertyInfo.PropertyType, () => propertyInfo, serviceProvider); if (convertedValue != null && !propertyInfo.PropertyType.IsInstanceOfType(convertedValue)) { return(false); } setter.Invoke(element, new object [] { convertedValue }); return(true); }
static bool TryAddValue(BindableObject bindable, BindableProperty property, object value, XamlServiceProvider serviceProvider) { if (property?.ReturnTypeInfo?.GenericTypeArguments == null) { return(false); } if (property.ReturnType == null) { return(false); } if (property.ReturnTypeInfo.GenericTypeArguments.Length != 1 || !property.ReturnTypeInfo.GenericTypeArguments[0].IsInstanceOfType(value)) { return(false); } // This might be a collection we can add to; see if we can find an Add method var addMethod = GetAllRuntimeMethods(property.ReturnType) .FirstOrDefault(mi => mi.Name == "Add" && mi.GetParameters().Length == 1); if (addMethod == null) { return(false); } // If there's an add method, get the collection var collection = bindable.GetValue(property); // And add the new value to it addMethod.Invoke(collection, new[] { value.ConvertTo(addMethod.GetParameters()[0].ParameterType, (Func <TypeConverter>)null, serviceProvider) }); return(true); }
static private object GetConvertedValue(Type valueType, object value, Func <MemberInfo> minfoRetriever, XamlServiceProvider serviceProvider) { try { object convertedValue = value.ConvertTo(valueType, minfoRetriever, serviceProvider); if (convertedValue != null && !valueType.IsInstanceOfType(convertedValue)) { return(null); } return(convertedValue); } catch { return(null); } }
static bool TrySetProperty(object element, string localName, object value, IXmlLineInfo lineInfo, XamlServiceProvider serviceProvider, HydrationContext context, out Exception exception) { exception = null; var elementType = element.GetType(); var propertyInfo = elementType.GetRuntimeProperties().FirstOrDefault(p => p.Name == localName); MethodInfo setter; if (propertyInfo == null || !propertyInfo.CanWrite || (setter = propertyInfo.SetMethod) == null) { return(false); } if (!IsVisibleFrom(setter, context.RootElement)) { return(false); } if (serviceProvider != null && serviceProvider.IProvideValueTarget != null) { ((XamlValueTargetProvider)serviceProvider.IProvideValueTarget).TargetProperty = propertyInfo; } object convertedValue = GetConvertedValue(propertyInfo.PropertyType, value, () => propertyInfo, serviceProvider); if (null == convertedValue) { var methods = propertyInfo.PropertyType.GetMethods().Where(a => a.Name == "op_Implicit"); foreach (var method in methods) { var paramType = method.GetParameters()[0].ParameterType; convertedValue = GetConvertedValue(paramType, value, () => propertyInfo, serviceProvider); if (null != convertedValue) { var realValue = Activator.CreateInstance(propertyInfo.PropertyType); convertedValue = method.Invoke(realValue, new object[] { convertedValue }); if (null != convertedValue) { break; } } } } if (null == convertedValue) { return(false); } setter.Invoke(element, new object[] { convertedValue }); return(true); }
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); if (value is Element) { if (null != Application.Current) { Application.AddResourceChangedCallback(value, (value as Element).OnResourcesChanged); } if (value is BindableObject) { ((BindableObject)value).IsCreateByXaml = true; } } } } 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); } }
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 (type == null) { throw new ArgumentNullException(null, "type should not be null"); } 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) { if (type.GetTypeInfo().DeclaredConstructors.Any(ci => ci.IsPublic && ci.GetParameters().Length == 0)) { //default constructor value = Activator.CreateInstance(type); } else { ConstructorInfo constructorInfo = null; //constructor with all default parameters foreach (var constructor in type.GetConstructors()) { if (!constructor.IsStatic) { bool areAllParamsDefault = true; foreach (var param in constructor.GetParameters()) { if (!param.HasDefaultValue) { areAllParamsDefault = false; break; } } if (areAllParamsDefault) { if (null == constructorInfo) { constructorInfo = constructor; } else { throw new XamlParseException($"{type.FullName} has more than one constructor which params are all default.", node); } } } } if (null == constructorInfo) { throw new XamlParseException($"{type.FullName} has no constructor which params are all default.", node); } List <object> defaultParams = new List <object>(); foreach (var param in constructorInfo.GetParameters()) { defaultParams.Add(param.DefaultValue); } value = Activator.CreateInstance(type, defaultParams.ToArray()); } if (value is Element element) { element.IsCreateByXaml = true; element.LineNumber = node.LineNumber; element.LinePosition = node.LinePosition; } } } 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); } }