/// <summary> /// Applies the binding to a property on an instance. /// </summary> /// <param name="instance">The target instance.</param> /// <param name="property">The target property.</param> public void Bind(IPerspexObject instance, PerspexProperty property) { var subject = CreateSubject(instance, property); if (subject != null) { Bind(instance, property, subject); } }
/// <summary> /// Creates a subject that can be used to get and set the value of the binding. /// </summary> /// <param name="target">The target instance.</param> /// <param name="targetProperty">The target property.</param> /// <returns>An <see cref="ISubject{Object}"/>.</returns> public ISubject<object> CreateSubject(IPerspexObject target, PerspexProperty targetProperty) { if (Converter == null) { throw new NotSupportedException("MultiBinding without Converter not currently supported."); } var targetType = targetProperty?.PropertyType ?? typeof(object); var result = new BehaviorSubject<object>(PerspexProperty.UnsetValue); var children = Bindings.Select(x => x.CreateSubject(target, null)); var input = children.CombineLatest().Select(x => ConvertValue(x, targetType)); input.Subscribe(result); return result; }
/// <summary> /// Creates a subject that can be used to get and set the value of the binding. /// </summary> /// <param name="target">The target instance.</param> /// <param name="targetProperty">The target property. May be null.</param> /// <returns>An <see cref="ISubject{Object}"/>.</returns> public ISubject<object> CreateSubject( IPerspexObject target, PerspexProperty targetProperty) { Contract.Requires<ArgumentNullException>(target != null); var pathInfo = ParsePath(Path); ValidateState(pathInfo); ExpressionObserver observer; if (pathInfo.ElementName != null || ElementName != null) { observer = CreateElementObserver( (IControl)target, pathInfo.ElementName ?? ElementName, pathInfo.Path); } else if (Source != null) { observer = CreateSourceObserver(Source, pathInfo.Path); } else if (RelativeSource == null || RelativeSource.Mode == RelativeSourceMode.DataContext) { observer = CreateDataContexObserver( target, pathInfo.Path, targetProperty == Control.DataContextProperty); } else if (RelativeSource.Mode == RelativeSourceMode.TemplatedParent) { observer = CreateTemplatedParentObserver(target, pathInfo.Path); } else { throw new NotSupportedException(); } return new ExpressionSubject( observer, targetProperty?.PropertyType ?? typeof(object), Converter ?? DefaultValueConverter.Instance, ConverterParameter, FallbackValue); }
private ExpressionObserver CreateTemplatedParentObserver( IPerspexObject target, string path) { Contract.Requires<ArgumentNullException>(target != null); var update = target.GetObservable(Control.TemplatedParentProperty) .Skip(1) .Select(_ => Unit.Default); var result = new ExpressionObserver( () => target.GetValue(Control.TemplatedParentProperty), path, update); return result; }
private ExpressionObserver CreateDataContexObserver( IPerspexObject target, string path, bool targetIsDataContext) { Contract.Requires<ArgumentNullException>(target != null); if (!targetIsDataContext) { var update = target.GetObservable(Control.DataContextProperty) .Skip(1) .Select(_ => Unit.Default); var result = new ExpressionObserver( () => target.GetValue(Control.DataContextProperty), path, update); return result; } else { return new ExpressionObserver( target.GetObservable(Visual.VisualParentProperty) .OfType<IPerspexObject>() .Select(x => x.GetObservable(Control.DataContextProperty)) .Switch(), path); } }
/// <summary> /// Applies a binding subject to a property on an instance. /// </summary> /// <param name="target">The target instance.</param> /// <param name="property">The target property.</param> /// <param name="subject">The binding subject.</param> internal void Bind(IPerspexObject target, PerspexProperty property, ISubject<object> subject) { var mode = Mode == BindingMode.Default ? property.DefaultBindingMode : Mode; switch (mode) { case BindingMode.Default: case BindingMode.OneWay: target.Bind(property, subject, Priority); break; case BindingMode.TwoWay: throw new NotSupportedException("TwoWay MultiBinding not currently supported."); case BindingMode.OneTime: target.GetObservable(Control.DataContextProperty).Subscribe(dataContext => { subject.Take(1).Subscribe(x => target.SetValue(property, x, Priority)); }); break; case BindingMode.OneWayToSource: target.GetObservable(property).Subscribe(subject); break; } }