コード例 #1
0
        /// <summary>
        /// <para>Converts NotificationObject's property to ReactiveProperty. Value is two-way synchronized.</para>
        /// <para>PropertyChanged raise on selected scheduler.</para>
        /// </summary>
        /// <typeparam name="TSubject">The type of the subject.</typeparam>
        /// <typeparam name="TProperty">The type of the property.</typeparam>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <param name="subject">The subject.</param>
        /// <param name="propertySelector">Argument is self, Return is target property.</param>
        /// <param name="convert">Convert selector to ReactiveProperty.</param>
        /// <param name="convertBack">Convert selector to source.</param>
        /// <param name="mode">ReactiveProperty mode.</param>
        /// <returns></returns>
        public static ReactivePropertySlim <TResult> ToReactivePropertySlimAsSynchronized <TSubject, TProperty, TResult>(
            this TSubject subject,
            Expression <Func <TSubject, TProperty> > propertySelector,
            Func <IObservable <TProperty>, IObservable <TResult> > convert,
            Func <IObservable <TResult>, IObservable <TProperty> > convertBack,
            ReactivePropertyMode mode = ReactivePropertyMode.DistinctUntilChanged | ReactivePropertyMode.RaiseLatestValueOnSubscribe)
            where TSubject : INotifyPropertyChanged
        {
            if (ExpressionTreeUtils.IsNestedPropertyPath(propertySelector))
            {
                var         result     = new ReactivePropertySlim <TResult>(mode: mode);
                var         observer   = PropertyObservable.CreateFromPropertySelector(subject, propertySelector);
                IDisposable disposable = null;
                disposable = convert(subject.ObserveProperty(propertySelector, isPushCurrentValueAtFirst: true))
                             .Subscribe(x => result.Value = x);
                convertBack(result)
                .Subscribe(x => observer.SetPropertyPathValue(x), _ => disposable.Dispose(), () => disposable.Dispose());
                return(result);
            }
            else
            {
                var setter = AccessorCache <TSubject> .LookupSet(propertySelector, out _);

                var         result     = new ReactivePropertySlim <TResult>(mode: mode);
                IDisposable disposable = null;
                disposable = convert(subject.ObserveProperty(propertySelector, isPushCurrentValueAtFirst: true))
                             .Subscribe(x => result.Value = x);
                convertBack(result)
                .Subscribe(x => setter(subject, x), _ => disposable.Dispose(), () => disposable.Dispose());
                return(result);
            }
        }
コード例 #2
0
        /// <summary>
        /// <para>Converts NotificationObject's property to ReactiveProperty. Value is two-way synchronized.</para>
        /// <para>PropertyChanged raise on selected scheduler.</para>
        /// </summary>
        /// <typeparam name="TSubject">The type of the subject.</typeparam>
        /// <typeparam name="TProperty">The type of the property.</typeparam>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <param name="subject">The subject.</param>
        /// <param name="propertySelector">Argument is self, Return is target property.</param>
        /// <param name="convert">Convert selector to ReactiveProperty.</param>
        /// <param name="convertBack">Convert selector to source.</param>
        /// <param name="raiseEventScheduler">The raise event scheduler.</param>
        /// <param name="mode">ReactiveProperty mode.</param>
        /// <param name="ignoreValidationErrorValue">Ignore validation error value.</param>
        /// <returns></returns>
        public static ReactiveProperty <TResult> ToReactivePropertyAsSynchronized <TSubject, TProperty, TResult>(
            this TSubject subject,
            Expression <Func <TSubject, TProperty> > propertySelector,
            Func <IObservable <TProperty>, IObservable <TResult> > convert,
            Func <IObservable <TResult>, IObservable <TProperty> > convertBack,
            IScheduler raiseEventScheduler,
            ReactivePropertyMode mode       = ReactivePropertyMode.DistinctUntilChanged | ReactivePropertyMode.RaiseLatestValueOnSubscribe,
            bool ignoreValidationErrorValue = false)
            where TSubject : INotifyPropertyChanged
        {
            if (ExpressionTreeUtils.IsNestedPropertyPath(propertySelector))
            {
                var observer = PropertyObservable.CreateFromPropertySelector(subject, propertySelector);
                var result   = convert(Observable.Using(() => observer, x => x)
                                       .StartWith(observer.GetPropertyPathValue()))
                               .ToReactiveProperty(raiseEventScheduler, mode: mode);
                convertBack(result.Where(_ => !ignoreValidationErrorValue || !result.HasErrors))
                .Subscribe(x => observer.SetPropertyPathValue(x));
                return(result);
            }
            else
            {
                var setter = AccessorCache <TSubject> .LookupSet(propertySelector, out _);

                var result = convert(subject.ObserveProperty(propertySelector, isPushCurrentValueAtFirst: true))
                             .ToReactiveProperty(raiseEventScheduler, mode: mode);
                convertBack(result.Where(_ => !ignoreValidationErrorValue || !result.HasErrors))
                .Subscribe(x => setter(subject, x));
                return(result);
            }
        }
コード例 #3
0
        public void ChangeObserveSourcePropertyType()
        {
            var item = new Item
            {
                Child = new Item
                {
                    Value = 10,
                },
            };

            var testScheduler = new TestScheduler();
            var testObserver  = testScheduler.CreateObserver <int>();

            var path = PropertyObservable.CreateFromPropertySelector(item, x => x.Child.Value);

            path.Subscribe(testObserver);
            path.GetPropertyPathValue().Is(10);
            item.Child.Value = 1;
            testObserver.Messages.Is(OnNext(0, 1));

            item.Child = new AnotherItem
            {
                Value = 9999,
            };
            path.GetPropertyPathValue().Is(9999);
            testObserver.Messages.Is(OnNext(0, 1), OnNext(0, 9999));
        }
コード例 #4
0
        public void ObserveProperty()
        {
            var item = new Item
            {
                Child = new Item
                {
                    Value = 10,
                },
            };

            var testScheduler = new TestScheduler();
            var testObserver  = testScheduler.CreateObserver <int>();

            var path = PropertyObservable.CreateFromPropertySelector(item, x => x.Child.Value);

            path.Subscribe(testObserver);
            path.GetPropertyPathValue().Is(10);
            item.Child.Value = 1;

            testObserver.Messages.Is(OnNext(0, 1));
            item.IsPropertyChangedEmpty.IsFalse();
            path.Dispose();
            item.IsPropertyChangedEmpty.IsTrue();
            item.Child.Value = 100;
            testObserver.Messages.Is(OnNext(0, 1));
        }
コード例 #5
0
        private static IObservable <TProperty> ObserveNestedProperty <TSubject, TProperty>(
            this TSubject subject, Expression <Func <TSubject, TProperty> > propertySelector,
            bool isPushCurrentValueAtFirst = true)
            where TSubject : INotifyPropertyChanged
        {
            var propertyObserver = PropertyObservable.CreateFromPropertySelector(subject, propertySelector);
            var ox = Observable.Using(() => propertyObserver, x => x);

            return(isPushCurrentValueAtFirst ?
                   ox.StartWith(propertyObserver.GetPropertyPathValue()) :
                   ox.AsObservable());
        }
コード例 #6
0
        public static PropertyObservable <TProperty> CreateFromPropertySelector <TSubject, TProperty>(TSubject subject, Expression <Func <TSubject, TProperty> > propertySelector)
            where TSubject : INotifyPropertyChanged
        {
            if (!(propertySelector.Body is MemberExpression current))
            {
                throw new ArgumentException();
            }

            var result = new PropertyObservable <TProperty>();

            result.SetRootNode(PropertyPathNode.CreateFromPropertySelector(propertySelector));
            result.SetSource(subject);
            return(result);
        }
コード例 #7
0
        public void ObserveReactiveProperty()
        {
            var rp            = new ReactiveProperty <ClassThatDoesNotImplementedINotifyPropertyChanged>();
            var testScheduler = new TestScheduler();
            var testObserver  = testScheduler.CreateObserver <string>();
            var path          = PropertyObservable.CreateFromPropertySelector(rp, x => x.Value.Name);

            path.Subscribe(testObserver);

            path.GetPropertyPathValue().IsNull();
            rp.Value = new ClassThatDoesNotImplementedINotifyPropertyChanged {
                Name = "name1"
            };
            path.GetPropertyPathValue().Is("name1");
        }