Example #1
0
        /// <summary>
        /// Writes trace output for a binding failure plus triggers the event <see cref="BindingDiagnostics.BindingFailed"/>.
        /// The event will not be triggered if the TraceEventType is filtered out. This overload allows specific trace and event parameters to be included.
        /// </summary>
        /// <param name="binding">The binding is only part of the event, not the trace message.</param>
        public static void TraceAndNotify(TraceEventType eventType, AvTraceDetails traceDetails, BindingExpressionBase binding, object[] traceParameters, object[] eventParameters = null)
        {
            string traceOutput = _avTrace.Trace(eventType, traceDetails.Id, traceDetails.Message, traceDetails.Labels, traceParameters);

            if (traceOutput != null && BindingDiagnostics.IsEnabled)
            {
                BindingDiagnostics.NotifyBindingFailed(new BindingFailedEventArgs(eventType, traceDetails.Id, traceOutput, binding, eventParameters));
            }
        }
Example #2
0
        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
            }
        }
Example #3
0
        /// <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);
            }
        }