Example #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);
            var 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);
            var 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);
        }
    }
    /// <summary>
    /// Data binding method.
    /// </summary>
    /// <typeparam name="TView">View type</typeparam>
    /// <typeparam name="TProperty">Property type</typeparam>
    /// <param name="self">View</param>
    /// <param name="propertySelector">Target property selector</param>
    /// <param name="source">Source property</param>
    /// <param name="updateSourceTrigger">Update source trigger</param>
    /// <returns>Data binding token</returns>
    public static IDisposable SetBindingTableViewDataSource <TView, TProperty>(
        this TView self,
        Expression <Func <TView, TProperty> > propertySelector,
        ReactiveProperty <TProperty> source, Func <TView, IObservable <Unit> > updateSourceTrigger = null)
        where TView : IUITableViewDataSource
    {
        var d = new CompositeDisposable();

        var isUpdating = false;
        var setter     = AccessorCache <TView> .LookupSet(propertySelector, out var propertyName);

        source
        .Where(_ => !isUpdating)
        .Subscribe(x => setter(self, x))
        .AddTo(d);
        if (updateSourceTrigger != null)
        {
            var getter = AccessorCache <TView> .LookupGet(propertySelector, out propertyName);

            updateSourceTrigger(self).Subscribe(_ =>
            {
                isUpdating = true;
                try
                {
                    source.Value = getter(self);
                }
                finally
                {
                    isUpdating = false;
                }
            }).AddTo(d);
        }

        return(d);
    }
Example #3
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 <TResult>(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 <TResult>(raiseEventScheduler, mode: mode);
            convertBack(result.Where(_ => !ignoreValidationErrorValue || !result.HasErrors))
            .Subscribe(x => setter(subject, x));
            return(result);
        }
    }
        private static IDisposable CreateTowWayBinding <T, TTarget, TProperty>(IReactiveProperty <T> self, TTarget target, Expression <Func <TTarget, TProperty> > propertySelector, Func <T, TProperty> convert, Func <TProperty, T> convertBack, IObservable <Unit> targetUpdateTrigger, TProperty propertyFallbackValue, T sourceFallbackValue)
        {
            if (targetUpdateTrigger == null)
            {
                throw new NotSupportedException("TwoWay binding required targetUpdateTrigger parameter.");
            }

            var propertyName   = default(string);
            var d              = new CompositeDisposable();
            var targetUpdating = false;
            var sourceUpdating = false;

            targetUpdateTrigger
            .Subscribe(_ =>
            {
                if (sourceUpdating)
                {
                    return;
                }

                targetUpdating = true;
                try
                {
                    self.Value = convertBack(AccessorCache <TTarget> .LookupGet(propertySelector, out propertyName)(target));
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                    self.Value = sourceFallbackValue;
                }
                targetUpdating = false;
            })
            .AddTo(d);
            self.Subscribe(value =>
            {
                if (targetUpdating)
                {
                    return;
                }

                var setter     = AccessorCache <TTarget> .LookupSet(propertySelector, out propertyName);
                sourceUpdating = true;
                try
                {
                    setter(target, convert(value));
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                    setter(target, propertyFallbackValue);
                }
                sourceUpdating = false;
            })
            .AddTo(d);
            return(d);
        }
    /// <summary>
    /// Data binding method.
    /// </summary>
    /// <typeparam name="TView">View type</typeparam>
    /// <typeparam name="TProperty">Property type</typeparam>
    /// <param name="self">View</param>
    /// <param name="propertySelector">Target property selector</param>
    /// <param name="source">Source property</param>
    /// <returns>Data binding token</returns>
    public static IDisposable SetBindingTableViewDataSource <TView, TProperty>(
        this TView self,
        Expression <Func <TView, TProperty> > propertySelector,
        ReadOnlyReactiveProperty <TProperty> source)
        where TView : IUITableViewDataSource
    {
        var d = new CompositeDisposable();

        var setter = AccessorCache <TView> .LookupSet(propertySelector, out var propertyName);

        source
        .Subscribe(x => setter(self, x))
        .AddTo(d);
        return(d);
    }
        /// <summary>
        /// Data binding method.
        /// </summary>
        /// <typeparam name="TView">View type</typeparam>
        /// <typeparam name="TProperty">Property type</typeparam>
        /// <param name="self">View</param>
        /// <param name="propertySelector">Target property selector</param>
        /// <param name="source">Source property</param>
        /// <returns>Data binding token</returns>
        public static IDisposable SetBindingGestureRecognizer <TView, TProperty>(
            this TView self,
            Expression <Func <TView, TProperty> > propertySelector,
            ReadOnlyReactiveProperty <TProperty> source)
            where TView : UIGestureRecognizer
        {
            var d = new CompositeDisposable();

            string propertyName;
            var    setter = AccessorCache <TView> .LookupSet(propertySelector, out propertyName);

            source
            .Subscribe(x => setter(self, x))
            .AddTo(d);
            return(d);
        }
Example #7
0
 private static IDisposable CreateOneWayBinding <T, TTarget, TProperty>(IObservable <T> self, TTarget target, Expression <Func <TTarget, TProperty> > propertySelector, Func <T, TProperty> convert, TProperty propertyFallbackValue)
 {
     return(self
            .Subscribe(value =>
     {
         var setter = AccessorCache <TTarget> .LookupSet(propertySelector, out var _);
         try
         {
             setter(target, convert(value));
         }
         catch (Exception ex)
         {
             Debug.WriteLine(ex);
             setter(target, propertyFallbackValue);
         }
     }));
 }
        /// <summary>
        /// Data binding method.
        /// </summary>
        /// <typeparam name="TView">View type</typeparam>
        /// <typeparam name="TProperty">Property type</typeparam>
        /// <param name="self">View</param>
        /// <param name="propertySelector">Target property selector</param>
        /// <param name="source">Source property</param>
        /// <returns>Data binding token</returns>
        public static IDisposable SetBinding <TView, TProperty>(
            this TView self,
            Expression <Func <TView, TProperty> > propertySelector,
            ReadOnlyReactiveProperty <TProperty> source)
            where TView : View
        {
            var d = new CompositeDisposable();

            bool   isUpdating = false;
            string propertyName;
            var    setter = AccessorCache <TView> .LookupSet(propertySelector, out propertyName);

            source
            .Where(_ => !isUpdating)
            .Subscribe(x => setter(self, x))
            .AddTo(d);
            return(d);
        }
        public void LookupGetAndSet()
        {
            var get = AccessorCache <Person> .LookupGet(p => p.Name, out var prop);

            Assert.AreEqual("Name", prop);

            var set = AccessorCache <Person> .LookupSet(p => p.Name, out prop);

            Assert.AreEqual("Name", prop);

            var person = new Person {
                Name = "tanaka"
            };

            get(person).Is("tanaka");
            set(person, "kimura");
            person.Name.Is("kimura");
        }
Example #10
0
    public bool SetPropertyPathValue(object?value)
    {
        if (Source == null)
        {
            return(false);
        }

        if (Next != null)
        {
            return(Next.SetPropertyPathValue(value));
        }
        else
        {
            var setter = _setAccessor ?? (_setAccessor = AccessorCache.LookupSet(Source.GetType(), PropertyName));
            setter.DynamicInvoke(Source, value);
            return(true);
        }
    }
Example #11
0
 public static IDisposable OneWayBind <TType, TProperty>(this TType type, Expression <Func <TType, TProperty> > selector,
                                                         IObservable <TProperty> observable)
 {
     return(observable.ObserveOnUIDispatcher()
            .Subscribe(x => { AccessorCache <TType> .LookupSet(selector).Invoke(type, x); }));
 }