Example #1
0
        /// <summary>
        /// BindTo takes an Observable stream and applies it to a target
        /// property. Conceptually it is similar to "Subscribe(x =&gt;
        /// target.property = x)", but allows you to use child properties
        /// without the null checks.
        /// </summary>
        /// <param name="target">The target object whose property will be set.</param>
        /// <param name="property">An expression representing the target
        /// property to set. This can be a child property (i.e. x.Foo.Bar.Baz).</param>
        /// <returns>An object that when disposed, disconnects the binding.</returns>
        public static IDisposable BindTo <TTarget, TValue>(
            this IObservable <TValue> This,
            TTarget target,
            Expression <Func <TTarget, TValue> > property)
            where TTarget : IReactiveNotifyPropertyChanged
        {
            var sourceSub = new MultipleAssignmentDisposable();
            var source    = This;

            var subscribify = new Action <TTarget, string[]>((tgt, propNames) => {
                if (sourceSub.Disposable != null)
                {
                    sourceSub.Disposable.Dispose();
                }

                object current  = tgt;
                PropertyInfo pi = null;
                foreach (var propName in propNames.SkipLast(1))
                {
                    if (current == null)
                    {
                        return;
                    }

                    pi      = RxApp.getPropertyInfoOrThrow(current.GetType(), propName);
                    current = pi.GetValue(current, null);
                }
                if (current == null)
                {
                    return;
                }

                pi = RxApp.getPropertyInfoOrThrow(current.GetType(), propNames.Last());
                sourceSub.Disposable = This.Subscribe(x => {
                    pi.SetValue(current, x, null);
                });
            });

            IDisposable[] toDispose     = new IDisposable[] { sourceSub, null };
            string[]      propertyNames = RxApp.expressionToPropertyNames(property);
            toDispose[1] = target.ObservableForProperty(property).Subscribe(_ => subscribify(target, propertyNames));

            subscribify(target, propertyNames);

            return(Disposable.Create(() => { toDispose[0].Dispose(); toDispose[1].Dispose(); }));
        }
Example #2
0
        /// <summary>
        /// Given a fully filled-out IObservedChange object, SetValueToProperty
        /// will apply it to the specified object (i.e. it will ensure that
        /// target.property == This.GetValue() and "replay" the observed change
        /// onto another object)
        /// </summary>
        /// <param name="target">The target object to apply the change to.</param>
        /// <param name="property">The target property to apply the change to.</param>
        public static void SetValueToProperty <TSender, TValue, TTarget>(
            this IObservedChange <TSender, TValue> This,
            TTarget target,
            Expression <Func <TTarget, TValue> > property)
        {
            object current = target;

            string[] propNames = RxApp.expressionToPropertyNames(property);

            PropertyInfo pi;

            foreach (var propName in propNames.SkipLast(1))
            {
                pi      = RxApp.getPropertyInfoOrThrow(current.GetType(), propName);
                current = pi.GetValue(current, null);
            }

            pi = RxApp.getPropertyInfoForProperty(current.GetType(), propNames.Last());
            pi.SetValue(current, This.GetValue(), null);
        }
Example #3
0
        /// <summary>
        /// Attempts to return the current value of a property given a
        /// notification that it has changed. If any property in the
        /// property expression is null, false is returned.
        /// </summary>
        /// <param name="changeValue">The value of the property expression.</param>
        /// <returns>True if the entire expression was able to be followed, false otherwise</returns>
        public static bool TryGetValue <TSender, TValue>(this IObservedChange <TSender, TValue> This, out TValue changeValue)
        {
            if (!Equals(This.Value, default(TValue)))
            {
                changeValue = This.Value;
                return(true);
            }

            object current = This.Sender;

            string[] propNames = null;
            lock (propStringToNameCache) { propNames = propStringToNameCache.Get(This.PropertyName); }

            PropertyInfo pi;

            foreach (var propName in propNames.SkipLast(1))
            {
                if (current == null)
                {
                    changeValue = default(TValue);
                    return(false);
                }

                pi      = RxApp.getPropertyInfoOrThrow(current.GetType(), propName);
                current = pi.GetValue(current, null);
            }

            if (current == null)
            {
                changeValue = default(TValue);
                return(false);
            }

            pi          = RxApp.getPropertyInfoOrThrow(current.GetType(), propNames.Last());
            changeValue = (TValue)pi.GetValue(current, null);
            return(true);
        }