private IEnumerable<BindingExpressionPart> GetPart(string part) { part = part.Trim(); if (part == string.Empty) throw new FormatException("Path contains an empty part"); BindingExpressionPart indexer = null; int lbIndex = part.IndexOf('['); if (lbIndex != -1) { int rbIndex = part.LastIndexOf(']'); if (rbIndex == -1) throw new FormatException("Indexer did not contain closing bracket"); int argLength = rbIndex - lbIndex - 1; if (argLength == 0) throw new FormatException("Indexer did not contain arguments"); string argString = part.Substring(lbIndex + 1, argLength); indexer = new BindingExpressionPart(this, argString, true); part = part.Substring(0, lbIndex); part = part.Trim(); } if (part.Length > 0) yield return new BindingExpressionPart(this, part); if (indexer != null) yield return indexer; }
internal void Unapply() { object sourceObject; if (_weakSource != null && _weakSource.TryGetTarget(out sourceObject)) { for (var i = 0; i < _parts.Count - 1; i++) { BindingExpressionPart part = _parts[i]; if (!part.IsSelf) { part.TryGetValue(sourceObject, out sourceObject); } var inpc = sourceObject as INotifyPropertyChanged; if (inpc != null) { inpc.PropertyChanged -= part.ChangeHandler; } } } _weakSource = null; _weakTarget = null; }
public void PropertyChanged(object sender, PropertyChangedEventArgs args) { BindingExpressionPart part = NextPart ?? this; string name = args.PropertyName; if (!string.IsNullOrEmpty(name)) { if (part.IsIndexer) { if (name.Contains("[")) { if (name != string.Format("{0}[{1}]", part.IndexerName, part.Content)) { return; } } else if (name != part.IndexerName) { return; } } else if (name != part.Content) { return; } } _expression.Apply(); // Device.BeginInvokeOnMainThread(() => _expression.Apply()); }
void ParsePath() { string p = Path.Trim(); var last = new BindingExpressionPart(this, "."); _parts.Add(last); if (p[0] == '.') { if (p.Length == 1) { return; } p = p.Substring(1); } string[] pathParts = p.Split('.'); for (var i = 0; i < pathParts.Length; i++) { foreach (BindingExpressionPart part in GetPart(pathParts[i])) { last.NextPart = part; _parts.Add(part); last = part; } } }
internal void Unapply() { object sourceObject; if (_weakSource != null && _weakSource.TryGetTarget(out sourceObject)) { for (var i = 0; i < _parts.Count - 1; i++) { BindingExpressionPart part = _parts[i]; if (!part.IsSelf) { part.TryGetValue(sourceObject, out sourceObject); } part.Unsubscribe(); } } if (_trackingTemplatedParent) { BindableObject target = null; if (_weakTarget?.TryGetTarget(out target) == true && target is Element elem) { elem.TemplatedParentChanged -= OnTargetTemplatedParentChanged; } } _weakSource = null; _weakTarget = null; ClearAncestryChangeSubscriptions(); }
bool TryConvert(BindingExpressionPart part, ref object value, Type convertTo, bool toTarget) { if (value == null) { return(true); } if ((toTarget && _targetProperty.TryConvert(ref value)) || (!toTarget && convertTo.IsInstanceOfType(value))) { return(true); } object original = value; try { var stringValue = value as string ?? string.Empty; // see: https://bugzilla.xamarin.com/show_bug.cgi?id=32871 // do not canonicalize "*.[.]"; "1." should not update bound BindableProperty if (stringValue.EndsWith(".", StringComparison.Ordinal) && DecimalTypes.Contains(convertTo)) { value = original; return(false); } // do not canonicalize "-0"; user will likely enter a period after "-0" if (stringValue == "-0" && DecimalTypes.Contains(convertTo)) { value = original; return(false); } value = Convert.ChangeType(value, convertTo, CultureInfo.InvariantCulture); return(true); } catch (InvalidCastException) { value = original; return(false); } catch (FormatException) { value = original; return(false); } catch (OverflowException) { value = original; return(false); } }
internal void Unapply() { object sourceObject; if (_weakSource != null && _weakSource.TryGetTarget(out sourceObject)) { for (var i = 0; i < _parts.Count - 1; i++) { BindingExpressionPart part = _parts[i]; if (!part.IsSelf) { part.TryGetValue(sourceObject, out sourceObject); } part.Unsubscribe(); } } _weakSource = null; _weakTarget = null; }
void ParsePath() { string p = Path.Trim(); var last = new BindingExpressionPart(this, "."); _parts.Add(last); if (p[0] == '.') { if (p.Length == 1) { return; } p = p.Substring(1); } string[] pathParts = p.Split(ExpressionSplit); for (var i = 0; i < pathParts.Length; i++) { string part = pathParts[i].Trim(); if (part == string.Empty) { throw new FormatException("Path contains an empty part"); } BindingExpressionPart indexer = null; int lbIndex = part.IndexOf("[", StringComparison.Ordinal); if (lbIndex != -1) { int rbIndex = part.LastIndexOf(']'); if (rbIndex == -1) { throw new FormatException("Indexer did not contain closing bracket"); } int argLength = rbIndex - lbIndex - 1; if (argLength == 0) { throw new FormatException("Indexer did not contain arguments"); } string argString = part.Substring(lbIndex + 1, argLength); indexer = new BindingExpressionPart(this, argString, true); part = part.Substring(0, lbIndex); part = part.Trim(); } if (part.Length > 0) { var next = new BindingExpressionPart(this, part); last.NextPart = next; _parts.Add(next); last = next; } if (indexer != null) { last.NextPart = indexer; _parts.Add(indexer); last = indexer; } } }
/// <summary> /// Applies the binding expression to a previously set source or target. /// </summary> void ApplyCore(object sourceObject, BindableObject target, BindableProperty property, bool fromTarget = false) { BindingMode mode = Binding.GetRealizedMode(_targetProperty); if ((mode == BindingMode.OneWay || mode == BindingMode.OneTime) && fromTarget) { return; } bool needsGetter = (mode == BindingMode.TwoWay && !fromTarget) || mode == BindingMode.OneWay || mode == BindingMode.OneTime; bool needsSetter = !needsGetter && ((mode == BindingMode.TwoWay && fromTarget) || mode == BindingMode.OneWayToSource); object current = sourceObject; BindingExpressionPart part = null; for (var i = 0; i < _parts.Count; i++) { part = _parts[i]; if (!part.IsSelf && current != null) { // Allow the object instance itself to provide its own TypeInfo TypeInfo currentType = current is IReflectableType reflectable?reflectable.GetTypeInfo() : current.GetType().GetTypeInfo(); if (part.LastGetter == null || !part.LastGetter.DeclaringType.GetTypeInfo().IsAssignableFrom(currentType)) { SetupPart(currentType, part); } if (i < _parts.Count - 1) { part.TryGetValue(current, out current); } } if (!part.IsSelf && current != null && ((needsGetter && part.LastGetter == null) || (needsSetter && part.NextPart == null && part.LastSetter == null))) { BindingDiagnostics.SendBindingFailure(Binding, current, target, property, "Binding", PropertyNotFoundErrorMessage, part.Content, current, target.GetType(), property.PropertyName); break; } if (part.NextPart != null && (mode == BindingMode.OneWay || mode == BindingMode.TwoWay) && current is INotifyPropertyChanged inpc) { part.Subscribe(inpc); } } Debug.Assert(part != null, "There should always be at least the self part in the expression."); if (needsGetter) { if (part.TryGetValue(current, out object value) || part.IsSelf) { value = Binding.GetSourceValue(value, property.ReturnType); } else { value = Binding.FallbackValue ?? property.GetDefaultValue(target); } if (!TryConvert(ref value, property, property.ReturnType, true)) { BindingDiagnostics.SendBindingFailure(Binding, current, target, property, "Binding", CannotConvertTypeErrorMessage, value, property.ReturnType); return; } target.SetValueCore(property, value, SetValueFlags.ClearDynamicResource, BindableObject.SetValuePrivateFlags.Default | BindableObject.SetValuePrivateFlags.Converted); } else if (needsSetter && part.LastSetter != null && current != null) { object value = Binding.GetTargetValue(target.GetValue(property), part.SetterType); if (!TryConvert(ref value, property, part.SetterType, false)) { BindingDiagnostics.SendBindingFailure(Binding, current, target, property, "Binding", CannotConvertTypeErrorMessage, value, part.SetterType); return; } object[] args; if (part.IsIndexer) { args = new object[part.Arguments.Length + 1]; part.Arguments.CopyTo(args, 0); args[args.Length - 1] = value; } else if (part.IsBindablePropertySetter) { args = new[] { part.BindablePropertyField, value }; } else { args = new[] { value }; } part.LastSetter.Invoke(current, args); } }
void SetupPart(TypeInfo sourceType, BindingExpressionPart part) { part.Arguments = null; part.LastGetter = null; part.LastSetter = null; PropertyInfo property = null; if (part.IsIndexer) { if (sourceType.IsArray) { int index; if (!int.TryParse(part.Content, out index)) { Log.Warning("Binding", "{0} could not be parsed as an index for a {1}", part.Content, sourceType); } else { part.Arguments = new object[] { index } }; part.LastGetter = sourceType.GetDeclaredMethod("Get"); part.LastSetter = sourceType.GetDeclaredMethod("Set"); part.SetterType = sourceType.GetElementType(); } DefaultMemberAttribute defaultMember = null; foreach (var attrib in sourceType.GetCustomAttributes(typeof(DefaultMemberAttribute), true)) { if (attrib is DefaultMemberAttribute d) { defaultMember = d; break; } } string indexerName = defaultMember != null ? defaultMember.MemberName : "Item"; part.IndexerName = indexerName; #if NETSTANDARD2_0 try { property = sourceType.GetDeclaredProperty(indexerName); } catch (AmbiguousMatchException) { // Get most derived instance of property foreach (var p in sourceType.GetProperties()) { if (p.Name == indexerName && (property == null || property.DeclaringType.IsAssignableFrom(property.DeclaringType))) { property = p; } } } #else property = sourceType.GetDeclaredProperty(indexerName); #endif if (property == null) //is the indexer defined on the base class? { property = sourceType.BaseType.GetProperty(indexerName); } if (property == null) //is the indexer defined on implemented interface ? { foreach (var implementedInterface in sourceType.ImplementedInterfaces) { property = implementedInterface.GetProperty(indexerName); if (property != null) { break; } } } if (property != null) { ParameterInfo parameter = null; ParameterInfo[] array = property.GetIndexParameters(); for (int i = 0; i < array.Length; i++) { parameter = array[i]; break; } if (parameter != null) { try { object arg = Convert.ChangeType(part.Content, parameter.ParameterType, CultureInfo.InvariantCulture); part.Arguments = new[] { arg }; } catch (FormatException) { } catch (InvalidCastException) { } catch (OverflowException) { } } } } else { TypeInfo type = sourceType; while (type != null && property == null) { property = type.GetDeclaredProperty(part.Content); type = type.BaseType?.GetTypeInfo(); } } if (property != null) { if (property.CanRead && property.GetMethod.IsPublic && !property.GetMethod.IsStatic) { part.LastGetter = property.GetMethod; } if (property.CanWrite && property.SetMethod.IsPublic && !property.SetMethod.IsStatic) { part.LastSetter = property.SetMethod; var lastSetterParameters = part.LastSetter.GetParameters(); part.SetterType = lastSetterParameters[lastSetterParameters.Length - 1].ParameterType; if (Binding.AllowChaining) { FieldInfo bindablePropertyField = sourceType.GetDeclaredField(part.Content + "Property"); if (bindablePropertyField != null && bindablePropertyField.FieldType == typeof(BindableProperty) && sourceType.ImplementedInterfaces.Contains(typeof(IElementController))) { MethodInfo setValueMethod = null; #if NETSTANDARD1_0 foreach (MethodInfo m in sourceType.AsType().GetRuntimeMethods()) { if (m.Name.EndsWith("IElementController.SetValueFromRenderer")) { ParameterInfo[] parameters = m.GetParameters(); if (parameters.Length == 2 && parameters[0].ParameterType == typeof(BindableProperty)) { setValueMethod = m; break; } } } #else setValueMethod = typeof(IElementController).GetMethod("SetValueFromRenderer", new[] { typeof(BindableProperty), typeof(object) }); #endif if (setValueMethod != null) { part.LastSetter = setValueMethod; part.IsBindablePropertySetter = true; part.BindablePropertyField = bindablePropertyField.GetValue(null); } } } } #if !NETSTANDARD1_0 TupleElementNamesAttribute tupleEltNames; if (property != null && part.NextPart != null && property.PropertyType.IsGenericType && (property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple <>) || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple <,>) || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple <, ,>) || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple <, , ,>) || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple <, , , ,>) || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple <, , , , ,>) || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple <, , , , , ,>) || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple <, , , , , , ,>)) && (tupleEltNames = property.GetCustomAttribute(typeof(TupleElementNamesAttribute)) as TupleElementNamesAttribute) != null) { //modify the nextPart to access the tuple item via the ITuple indexer var nextPart = part.NextPart; var name = nextPart.Content; var index = tupleEltNames.TransformNames.IndexOf(name); if (index >= 0) { nextPart.IsIndexer = true; nextPart.Content = index.ToString(); } } #endif } }
/// <summary> /// Applies the binding expression to a previously set source or target. /// </summary> void ApplyCore(object sourceObject, BindableObject target, BindableProperty property, bool fromTarget = false) { BindingMode mode = Binding.GetRealizedMode(_targetProperty); if ((mode == BindingMode.OneWay || mode == BindingMode.OneTime) && fromTarget) { return; } bool needsGetter = (mode == BindingMode.TwoWay && !fromTarget) || mode == BindingMode.OneWay || mode == BindingMode.OneTime; bool needsSetter = !needsGetter && ((mode == BindingMode.TwoWay && fromTarget) || mode == BindingMode.OneWayToSource); object current = sourceObject; object previous = null; BindingExpressionPart part = null; for (var i = 0; i < _parts.Count; i++) { part = _parts[i]; bool isLast = i + 1 == _parts.Count; if (!part.IsSelf && current != null) { // Allow the object instance itself to provide its own TypeInfo var reflectable = current as IReflectableType; System.Reflection.TypeInfo currentType = reflectable != null?reflectable.GetTypeInfo() : current.GetType().GetTypeInfo(); if (part.LastGetter == null || !part.LastGetter.DeclaringType.GetTypeInfo().IsAssignableFrom(currentType)) { SetupPart(currentType, part); } if (!isLast) { part.TryGetValue(current, out current); } } if (!part.IsSelf && current != null) { if ((needsGetter && part.LastGetter == null) || (needsSetter && part.NextPart == null && part.LastSetter == null)) { Console.WriteLine("Binding, " + PropertyNotFoundErrorMessage, part.Content, current, target.GetType(), property.PropertyName); break; } } if (mode == BindingMode.OneWay || mode == BindingMode.TwoWay) { var inpc = current as INotifyPropertyChanged; if (inpc != null && !ReferenceEquals(current, previous)) { part.Subscribe(inpc); } } previous = current; } Debug.Assert(part != null, "There should always be at least the self part in the expression."); if (needsGetter) { object value = property.DefaultValue; if (part.TryGetValue(current, out value) || part.IsSelf) { value = Binding.GetSourceValue(value, property.ReturnType); } else { value = property.DefaultValue; } if (!TryConvert(ref value, property.ReturnType, true)) { Console.WriteLine($"Binding : {value} can not be converted to type {property.ReturnType}"); return; } target.SetValueCore(property, value, SetValueFlags.ClearDynamicResource, BindableObject.SetValuePrivateFlags.Default | BindableObject.SetValuePrivateFlags.Converted, false); } else if (needsSetter && part.LastSetter != null && current != null) { object value = Binding.GetTargetValue(target.GetValue(property), part.SetterType); if (!TryConvert(ref value, part.SetterType, false)) { Console.WriteLine($"Binding : {value} can not be converted to type {part.SetterType}"); return; } object[] args; if (part.IsIndexer) { args = new object[part.Arguments.Length + 1]; part.Arguments.CopyTo(args, 0); args[args.Length - 1] = value; } else if (part.IsBindablePropertySetter) { args = new[] { part.BindablePropertyField, value }; } else { args = new[] { value }; } part.LastSetter.Invoke(current, args); } }
IEnumerable<BindingExpressionPart> GetPart(string part) { part = part.Trim(); if (part == string.Empty) throw new FormatException("Path contains an empty part"); BindingExpressionPart indexer = null; int lbIndex = part.IndexOf('['); if (lbIndex != -1) { int rbIndex = part.LastIndexOf(']'); if (rbIndex == -1) throw new FormatException("Indexer did not contain closing bracket"); int argLength = rbIndex - lbIndex - 1; if (argLength == 0) throw new FormatException("Indexer did not contain arguments"); string argString = part.Substring(lbIndex + 1, argLength); indexer = new BindingExpressionPart(this, argString, true); part = part.Substring(0, lbIndex); part = part.Trim(); } if (part.Length > 0) yield return new BindingExpressionPart(this, part); if (indexer != null) yield return indexer; }
void SetupPart(TypeInfo sourceType, BindingExpressionPart part) { part.Arguments = null; part.LastGetter = null; part.LastSetter = null; PropertyInfo property = null; if (part.IsIndexer) { if (sourceType.IsArray) { if (!int.TryParse(part.Content, out var index)) { BindingDiagnostics.SendBindingFailure(Binding, "Binding", ParseIndexErrorMessage, part.Content, sourceType); } else { part.Arguments = new object[] { index } }; part.LastGetter = sourceType.GetDeclaredMethod("Get"); part.LastSetter = sourceType.GetDeclaredMethod("Set"); part.SetterType = sourceType.GetElementType(); } string indexerName = "Item"; foreach (DefaultMemberAttribute attrib in sourceType.GetCustomAttributes(typeof(DefaultMemberAttribute), true)) { indexerName = attrib.MemberName; break; } part.IndexerName = indexerName; property = GetIndexer(sourceType, indexerName, part.Content); if (property != null) { ParameterInfo parameter = null; ParameterInfo[] array = property.GetIndexParameters(); if (array.Length > 0) { parameter = array[0]; } if (parameter != null) { try { object arg = Convert.ChangeType(part.Content, parameter.ParameterType, CultureInfo.InvariantCulture); part.Arguments = new[] { arg }; } catch (FormatException) { } catch (InvalidCastException) { } catch (OverflowException) { } } } } else { TypeInfo type = sourceType; while (type != null && property == null) { property = type.GetDeclaredProperty(part.Content); type = type.BaseType?.GetTypeInfo(); } } if (property != null) { if (property.CanRead && property.GetMethod.IsPublic && !property.GetMethod.IsStatic) { part.LastGetter = property.GetMethod; } if (property.CanWrite && property.SetMethod.IsPublic && !property.SetMethod.IsStatic) { part.LastSetter = property.SetMethod; var lastSetterParameters = part.LastSetter.GetParameters(); part.SetterType = lastSetterParameters[lastSetterParameters.Length - 1].ParameterType; if (Binding.AllowChaining) { FieldInfo bindablePropertyField = sourceType.GetDeclaredField(part.Content + "Property"); if (bindablePropertyField != null && bindablePropertyField.FieldType == typeof(BindableProperty) && sourceType.ImplementedInterfaces.Contains(typeof(IElementController))) { MethodInfo setValueMethod = null; #if NETSTANDARD1_0 foreach (MethodInfo m in sourceType.AsType().GetRuntimeMethods()) { if (m.Name.EndsWith("IElementController.SetValueFromRenderer")) { ParameterInfo[] parameters = m.GetParameters(); if (parameters.Length == 2 && parameters[0].ParameterType == typeof(BindableProperty)) { setValueMethod = m; break; } } } #else setValueMethod = typeof(IElementController).GetMethod("SetValueFromRenderer", new[] { typeof(BindableProperty), typeof(object) }); #endif if (setValueMethod != null) { part.LastSetter = setValueMethod; part.IsBindablePropertySetter = true; part.BindablePropertyField = bindablePropertyField.GetValue(null); } } } } #if !NETSTANDARD1_0 if (property != null && part.NextPart != null && property.PropertyType.IsGenericType && (property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple <>) || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple <,>) || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple <, ,>) || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple <, , ,>) || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple <, , , ,>) || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple <, , , , ,>) || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple <, , , , , ,>) || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple <, , , , , , ,>)) && property.GetCustomAttribute(typeof(TupleElementNamesAttribute)) is TupleElementNamesAttribute tupleEltNames) { //modify the nextPart to access the tuple item via the ITuple indexer var nextPart = part.NextPart; var name = nextPart.Content; var index = tupleEltNames.TransformNames.IndexOf(name); if (index >= 0) { nextPart.IsIndexer = true; nextPart.Content = index.ToString(); } } #endif } }
void SetupPart(TypeInfo sourceType, BindingExpressionPart part) { part.Arguments = null; part.LastGetter = null; part.LastSetter = null; PropertyInfo property = null; if (part.IsIndexer) { if (sourceType.IsArray) { int index; if (!int.TryParse(part.Content, out index)) { Log.Warning("Binding", "{0} could not be parsed as an index for a {1}", part.Content, sourceType); } else { part.Arguments = new object[] { index } }; part.LastGetter = sourceType.GetDeclaredMethod("Get"); part.LastSetter = sourceType.GetDeclaredMethod("Set"); part.SetterType = sourceType.GetElementType(); } DefaultMemberAttribute defaultMember = sourceType.GetCustomAttributes(typeof(DefaultMemberAttribute), true).OfType <DefaultMemberAttribute>().FirstOrDefault(); string indexerName = defaultMember != null ? defaultMember.MemberName : "Item"; part.IndexerName = indexerName; property = sourceType.GetDeclaredProperty(indexerName); if (property == null) //is the indexer defined on the base class? { property = sourceType.BaseType.GetProperty(indexerName); } if (property == null) //is the indexer defined on implemented interface ? { foreach (var implementedInterface in sourceType.ImplementedInterfaces) { property = implementedInterface.GetProperty(indexerName); if (property != null) { break; } } } if (property != null) { ParameterInfo parameter = property.GetIndexParameters().FirstOrDefault(); if (parameter != null) { try { object arg = Convert.ChangeType(part.Content, parameter.ParameterType, CultureInfo.InvariantCulture); part.Arguments = new[] { arg }; } catch (FormatException) { } catch (InvalidCastException) { } catch (OverflowException) { } } } } else { property = sourceType.GetDeclaredProperty(part.Content) ?? sourceType.BaseType?.GetProperty(part.Content); } if (property != null) { if (property.CanRead && property.GetMethod.IsPublic && !property.GetMethod.IsStatic) { part.LastGetter = property.GetMethod; } if (property.CanWrite && property.SetMethod.IsPublic && !property.SetMethod.IsStatic) { part.LastSetter = property.SetMethod; part.SetterType = part.LastSetter.GetParameters().Last().ParameterType; if (Binding.AllowChaining) { FieldInfo bindablePropertyField = sourceType.GetDeclaredField(part.Content + "Property"); if (bindablePropertyField != null && bindablePropertyField.FieldType == typeof(BindableProperty) && sourceType.ImplementedInterfaces.Contains(typeof(IElementController))) { MethodInfo setValueMethod = typeof(IElementController).GetMethod("SetValueFromRenderer", new[] { typeof(BindableProperty), typeof(object) }); if (setValueMethod != null) { part.LastSetter = setValueMethod; part.IsBindablePropertySetter = true; part.BindablePropertyField = bindablePropertyField.GetValue(null); } } } } TupleElementNamesAttribute tupleEltNames; if (property != null && part.NextPart != null && property.PropertyType.IsGenericType && (property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple <>) || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple <,>) || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple <, ,>) || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple <, , ,>) || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple <, , , ,>) || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple <, , , , ,>) || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple <, , , , , ,>) || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple <, , , , , , ,>)) && (tupleEltNames = property.GetCustomAttribute(typeof(TupleElementNamesAttribute)) as TupleElementNamesAttribute) != null) { //modify the nextPart to access the tuple item via the ITuple indexer var nextPart = part.NextPart; var name = nextPart.Content; var index = tupleEltNames.TransformNames.IndexOf(name); if (index >= 0) { nextPart.IsIndexer = true; nextPart.Content = index.ToString(); } } } }
public BindingPair(BindingExpressionPart part, object source, bool isLast) { Part = part; Source = source; IsLast = isLast; }
bool TryConvert(BindingExpressionPart part, ref object value, Type convertTo, bool toTarget) { if (value == null) return true; if ((toTarget && _targetProperty.TryConvert(ref value)) || (!toTarget && convertTo.IsInstanceOfType(value))) return true; object original = value; try { value = Convert.ChangeType(value, convertTo, CultureInfo.InvariantCulture); return true; } catch (InvalidCastException) { value = original; return false; } catch (FormatException) { value = original; return false; } catch (OverflowException) { value = original; return false; } }
void SetupPart(TypeInfo sourceType, BindingExpressionPart part) { part.Arguments = null; part.LastGetter = null; part.LastSetter = null; PropertyInfo property = null; if (part.IsIndexer) { if (sourceType.IsArray) { int index; if (!int.TryParse(part.Content, out index)) Log.Warning("Binding", "{0} could not be parsed as an index for a {1}", part.Content, sourceType); else part.Arguments = new object[] { index }; part.LastGetter = sourceType.GetDeclaredMethod("Get"); part.LastSetter = sourceType.GetDeclaredMethod("Set"); part.SetterType = sourceType.GetElementType(); } DefaultMemberAttribute defaultMember = sourceType.GetCustomAttributes(typeof(DefaultMemberAttribute), true).OfType<DefaultMemberAttribute>().FirstOrDefault(); string indexerName = defaultMember != null ? defaultMember.MemberName : "Item"; part.IndexerName = indexerName; property = sourceType.GetDeclaredProperty(indexerName); if (property == null) property = sourceType.BaseType.GetProperty(indexerName); if (property != null) { ParameterInfo parameter = property.GetIndexParameters().FirstOrDefault(); if (parameter != null) { try { object arg = Convert.ChangeType(part.Content, parameter.ParameterType, CultureInfo.InvariantCulture); part.Arguments = new[] { arg }; } catch (FormatException) { } catch (InvalidCastException) { } catch (OverflowException) { } } } } else { property = sourceType.GetDeclaredProperty(part.Content); if (property == null) property = sourceType.BaseType.GetProperty(part.Content); } if (property != null) { if (property.CanRead && property.GetMethod.IsPublic && !property.GetMethod.IsStatic) part.LastGetter = property.GetMethod; if (property.CanWrite && property.SetMethod.IsPublic && !property.SetMethod.IsStatic) { part.LastSetter = property.SetMethod; part.SetterType = part.LastSetter.GetParameters().Last().ParameterType; if (Binding.AllowChaining) { FieldInfo bindablePropertyField = sourceType.GetDeclaredField(part.Content + "Property"); if (bindablePropertyField != null && bindablePropertyField.FieldType == typeof(BindableProperty) && sourceType.ImplementedInterfaces.Contains(typeof(IElementController))) { MethodInfo setValueMethod = null; foreach (MethodInfo m in sourceType.AsType().GetRuntimeMethods()) { if (m.Name.EndsWith("IElementController.SetValueFromRenderer")) { ParameterInfo[] parameters = m.GetParameters(); if (parameters.Length == 2 && parameters[0].ParameterType == typeof(BindableProperty)) { setValueMethod = m; break; } } } if (setValueMethod != null) { part.LastSetter = setValueMethod; part.IsBindablePropertySetter = true; part.BindablePropertyField = bindablePropertyField.GetValue(null); } } } } } }
void ParsePath() { string p = Path.Trim(); var last = new BindingExpressionPart(this, "."); _parts.Add(last); if (p[0] == '.') { if (p.Length == 1) return; p = p.Substring(1); } string[] pathParts = p.Split('.'); for (var i = 0; i < pathParts.Length; i++) { foreach (BindingExpressionPart part in GetPart(pathParts[i])) { last.NextPart = part; _parts.Add(part); last = part; } } }
private void SetupPart(TypeInfo sourceType, BindingExpressionPart part) { part.Arguments = null; part.LastGetter = null; part.LastSetter = null; PropertyInfo property = null; if (part.IsIndexer) { if (sourceType.IsArray) { int index; if (!int.TryParse(part.Content, out index)) Log.Warning("Binding", "{0} could not be parsed as an index for a {1}", part.Content, sourceType); else part.Arguments = new object[] { index }; part.LastGetter = sourceType.GetDeclaredMethod("Get"); part.LastSetter = sourceType.GetDeclaredMethod("Set"); part.SetterType = sourceType.GetElementType(); } DefaultMemberAttribute defaultMember = sourceType.GetCustomAttributes(typeof(DefaultMemberAttribute), true).OfType<DefaultMemberAttribute>().FirstOrDefault(); string indexerName = defaultMember != null ? defaultMember.MemberName : "Item"; part.IndexerName = indexerName; property = sourceType.GetDeclaredProperty(indexerName); if (property == null) property = sourceType.BaseType.GetProperty(indexerName); if (property != null) { ParameterInfo parameter = property.GetIndexParameters().FirstOrDefault(); if (parameter != null) { try { object arg = Convert.ChangeType(part.Content, parameter.ParameterType, CultureInfo.InvariantCulture); part.Arguments = new[] { arg }; } catch (FormatException) { } catch (InvalidCastException) { } catch (OverflowException) { } } } } else { property = sourceType.GetDeclaredProperty(part.Content); if (property == null) property = sourceType.BaseType.GetProperty(part.Content); } if (property != null) { if (property.CanRead && property.GetMethod.IsPublic && !property.GetMethod.IsStatic) part.LastGetter = property.GetMethod; if (property.CanWrite && property.SetMethod.IsPublic && !property.SetMethod.IsStatic) { part.LastSetter = property.SetMethod; part.SetterType = part.LastSetter.GetParameters().Last().ParameterType; if (Binding.AllowChaining) { FieldInfo bindablePropertyField = sourceType.GetDeclaredField(part.Content + "Property"); if (bindablePropertyField != null && bindablePropertyField.FieldType == typeof(BindableProperty) && sourceType.ImplementedInterfaces.Contains(typeof(IElementController))) { MethodInfo setValueMethod = null; foreach (MethodInfo m in sourceType.AsType().GetRuntimeMethods()) { if (m.Name.EndsWith("IElementController.SetValueFromRenderer")) { ParameterInfo[] parameters = m.GetParameters(); if (parameters.Length == 2 && parameters[0].ParameterType == typeof(BindableProperty)) { setValueMethod = m; break; } } } if (setValueMethod != null) { part.LastSetter = setValueMethod; part.IsBindablePropertySetter = true; part.BindablePropertyField = bindablePropertyField.GetValue(null); } } } } } }