/// <summary>
		/// Constructs the exception and passes a meaningful
		/// message to the base Exception
		/// </summary>
		/// <param name="bindable">The bindable object that was passed</param>
		/// <param name="expected">The expected type</param>
		/// <param name="name">The calling methods name, uses [CallerMemberName]</param>
		public InvalidBindableException(BindableObject bindable, Type expected,[CallerMemberName]string name=null) 
			: base(string.Format("Invalid bindable passed to {0} expected a {1} received a {2}", name, expected.Name, bindable.GetType().Name))
		{
		}
Example #2
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 && fromTarget)
				return;

			bool needsGetter = (mode == BindingMode.TwoWay && !fromTarget) || mode == BindingMode.OneWay;
			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;
					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))
					{
						Log.Warning("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))
					{
						// If we're reapplying, we don't want to double subscribe
						inpc.PropertyChanged -= part.ChangeHandler;
						inpc.PropertyChanged += part.ChangeHandler;
					}
				}

				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(part, ref value, property.ReturnType, true))
				{
					Log.Warning("Binding", "{0} can not be converted to type '{1}'", value, property.ReturnType);
					return;
				}

				target.SetValueCore(property, value, BindableObject.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(part, ref value, part.SetterType, false))
				{
					Log.Warning("Binding", "{0} can not be converted to type '{1}'", 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);
			}
		}