Esempio n. 1
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>
 internal static void SetValueToProperty <TSender, TValue, TTarget>(
     this IObservedChange <TSender, TValue> This,
     TTarget target,
     Expression <Func <TTarget, TValue> > property)
 {
     Reflection.TrySetValueToPropertyChain(target, Reflection.Rewrite(property.Body).GetExpressionChain(), This.GetValue());
 }
Esempio n. 2
0
        private IReactiveBinding <TView, TViewModel, Tuple <object, bool> > BindImpl <TViewModel, TView, TVMProp, TVProp, TDontCare>(
            TViewModel viewModel,
            TView view,
            Expression <Func <TViewModel, TVMProp> > vmProperty,
            Expression <Func <TView, TVProp> > viewProperty,
            IObservable <TDontCare> signalViewUpdate,
            OutFunc <TVMProp, TVProp> vmToViewConverter,
            OutFunc <TVProp, TVMProp> viewToVmConverter)
            where TView : class, IViewFor
            where TViewModel : class
        {
            var signalInitialUpdate = new Subject <bool>();
            var vmExpression        = Reflection.Rewrite(vmProperty.Body);
            var viewExpression      = Reflection.Rewrite(viewProperty.Body);

            var signalObservable = signalViewUpdate != null
                                       ? signalViewUpdate.Select(_ => false)
                                       : view.WhenAnyDynamic(viewExpression, x => (TVProp)x.Value).Select(_ => false);

            var somethingChanged = Observable.Merge(
                Reflection.ViewModelWhenAnyValue(viewModel, view, vmExpression).Select(_ => true),
                signalInitialUpdate.Select(_ => true),
                signalObservable);

            var changeWithValues = somethingChanged.Select(isVm =>
            {
                TVMProp vmValue;
                TVProp vValue;
                if (!Reflection.TryGetValueForPropertyChain(out vmValue, view.ViewModel, vmExpression.GetExpressionChain()) ||
                    !Reflection.TryGetValueForPropertyChain(out vValue, view, viewExpression.GetExpressionChain()))
                {
                    return(null);
                }

                if (isVm)
                {
                    TVProp vmAsView;
                    if (!vmToViewConverter(vmValue, out vmAsView) || EqualityComparer <TVProp> .Default.Equals(vValue, vmAsView))
                    {
                        return(null);
                    }

                    return(Tuple.Create((object)vmAsView, isVm));
                }

                TVMProp vAsViewModel;
                if (!viewToVmConverter(vValue, out vAsViewModel) || EqualityComparer <TVMProp> .Default.Equals(vmValue, vAsViewModel))
                {
                    return(null);
                }

                return(Tuple.Create((object)vAsViewModel, isVm));
            });

            var ret = EvalBindingHooks(viewModel, view, vmExpression, viewExpression, BindingDirection.TwoWay);

            if (!ret)
            {
                return(null);
            }

            IObservable <Tuple <object, bool> > changes = changeWithValues.Where(tuple => tuple != null).Publish().RefCount();

            IDisposable disp = changes.Subscribe(isVmWithLatestValue =>
            {
                if (isVmWithLatestValue.Item2)
                {
                    Reflection.TrySetValueToPropertyChain(view, viewExpression.GetExpressionChain(), isVmWithLatestValue.Item1, false);
                }
                else
                {
                    Reflection.TrySetValueToPropertyChain(view.ViewModel, vmExpression.GetExpressionChain(), isVmWithLatestValue.Item1, false);
                }
            });

            // NB: Even though it's technically a two-way bind, most people
            // want the ViewModel to win at first.
            signalInitialUpdate.OnNext(true);

            return(new ReactiveBinding <TView, TViewModel, Tuple <object, bool> >(
                       view,
                       viewModel,
                       viewExpression,
                       vmExpression,
                       changes,
                       BindingDirection.TwoWay,
                       disp));
        }