Esempio n. 1
0
        public IDisposable OneWayBind <TViewModel, TView, TVMProp, TVProp>(
            TViewModel viewModel,
            TView view,
            Expression <Func <TViewModel, TVMProp> > vmProperty,
            Expression <Func <TView, TVProp> > viewProperty,
            Func <TVMProp> fallbackValue = null,
            object conversionHint        = null)
            where TViewModel : class
            where TView : IViewFor
        {
            if (viewProperty == null)
            {
                var viewPropChain = Reflection.getDefaultViewPropChain(view, Reflection.ExpressionToPropertyNames(vmProperty));

                var viewType  = Reflection.GetTypesForPropChain(typeof(TView), viewPropChain).Last();
                var converter = getConverterForTypes(typeof(TVMProp), viewType);

                if (converter == null)
                {
                    throw new ArgumentException(String.Format("Can't convert {0} to {1}. To fix this, register a IBindingTypeConverter", typeof(TVMProp), viewType));
                }

                return(Reflection.ViewModelWhenAnyValue(viewModel, view, vmProperty)
                       .SelectMany(x => {
                    object tmp;
                    if (!converter.TryConvert(x, viewType, conversionHint, out tmp))
                    {
                        return Observable.Empty <object>();
                    }
                    return Observable.Return(tmp);
                })
                       .Subscribe(x => Reflection.SetValueToPropertyChain(view, viewPropChain, x, false)));
            }
            else
            {
                var converter = getConverterForTypes(typeof(TVMProp), typeof(TVProp));

                if (converter == null)
                {
                    throw new ArgumentException(String.Format("Can't convert {0} to {1}. To fix this, register a IBindingTypeConverter", typeof(TVMProp), typeof(TVProp)));
                }

                return(Reflection.ViewModelWhenAnyValue(viewModel, view, vmProperty)
                       .SelectMany(x => {
                    object tmp;
                    if (!converter.TryConvert(x, typeof(TVProp), conversionHint, out tmp))
                    {
                        return Observable.Empty <TVProp>();
                    }
                    return Observable.Return(tmp == null ? default(TVProp) : (TVProp)tmp);
                })
                       .BindTo(view, viewProperty, () => {
                    object tmp;
                    return converter.TryConvert(fallbackValue(), typeof(TVProp), conversionHint, out tmp) ?  (TVProp)tmp : default(TVProp);
                }));
            }
        }
Esempio n. 2
0
        public IDisposable AsyncOneWayBind <TViewModel, TView, TProp, TOut>(
            TViewModel viewModel,
            TView view,
            Expression <Func <TViewModel, TProp> > vmProperty,
            Expression <Func <TView, TOut> > viewProperty,
            Func <TProp, IObservable <TOut> > selector,
            Func <TOut> fallbackValue = null)
            where TViewModel : class
            where TView : IViewFor
        {
            if (viewProperty == null)
            {
                var viewPropChain = Reflection.getDefaultViewPropChain(view, Reflection.ExpressionToPropertyNames(vmProperty));

                return(Reflection.ViewModelWhenAnyValue(viewModel, view, vmProperty)
                       .SelectMany(selector)
                       .Subscribe(x => Reflection.SetValueToPropertyChain(view, viewPropChain, x, false)));
            }

            return(Reflection.ViewModelWhenAnyValue(viewModel, view, vmProperty)
                   .SelectMany(selector)
                   .BindTo(view, viewProperty, fallbackValue));
        }
Esempio n. 3
0
        public IDisposable Bind <TViewModel, TView, TVMProp, TVProp, TDontCare>(
            TViewModel viewModel,
            TView view,
            Expression <Func <TViewModel, TVMProp> > vmProperty,
            Expression <Func <TView, TVProp> > viewProperty,
            IObservable <TDontCare> signalViewUpdate,
            object conversionHint)
            where TViewModel : class
            where TView : IViewFor
        {
            var signalInitialUpdate = new Subject <bool>();
            var vmPropChain         = Reflection.ExpressionToPropertyNames(vmProperty);

            string[] viewPropChain;

            if (viewProperty == null)
            {
                viewPropChain = Reflection.getDefaultViewPropChain(view, vmPropChain);
            }
            else
            {
                viewPropChain = Reflection.ExpressionToPropertyNames(viewProperty);
            }

            var vmToViewConverter = getConverterForTypes(typeof(TVMProp), typeof(TVProp));
            var viewToVMConverter = getConverterForTypes(typeof(TVProp), typeof(TVMProp));

            if (vmToViewConverter == null || viewToVMConverter == null)
            {
                throw new ArgumentException(
                          String.Format("Can't two-way convert between {0} and {1}. To fix this, register a IBindingTypeConverter", typeof(TVMProp), typeof(TVProp)));
            }

            var somethingChanged = Observable.Merge(
                Reflection.ViewModelWhenAnyValue(viewModel, view, vmProperty).Select(_ => true),
                signalInitialUpdate,
                signalViewUpdate != null ?
                signalViewUpdate.Select(_ => false) :
                view.WhenAnyDynamic(viewPropChain, x => (TVProp)x.Value).Select(_ => false));

            string vmChangedString = String.Format("Setting {0}.{1} => {2}.{3}: ",
                                                   typeof(TViewModel).Name, String.Join(".", vmPropChain),
                                                   typeof(TView).Name, String.Join(".", viewPropChain));

            string viewChangedString = String.Format("Setting {0}.{1} => {2}.{3}: ",
                                                     typeof(TView).Name, String.Join(".", viewPropChain),
                                                     typeof(TViewModel).Name, String.Join(".", vmPropChain));

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

                if (isVm)
                {
                    var vmAsView = (TVProp)vmToViewConverter.Convert(vmValue, typeof(TVProp), conversionHint);
                    var changed  = EqualityComparer <TVProp> .Default.Equals(vValue, vmAsView) != true;
                    if (!changed)
                    {
                        return(null);
                    }

                    this.Log().Info(vmChangedString + (vmAsView != null ? vmAsView.ToString() : "(null)"));
                    return(Tuple.Create((object)vmAsView, isVm));
                }
                else
                {
                    var vAsViewModel = (TVMProp)viewToVMConverter.Convert(vValue, typeof(TVMProp), conversionHint);
                    var changed      = EqualityComparer <TVMProp> .Default.Equals(vmValue, vAsViewModel) != true;
                    if (!changed)
                    {
                        return(null);
                    }

                    this.Log().Info(viewChangedString + (vAsViewModel != null ? vAsViewModel.ToString() : "(null)"));
                    return(Tuple.Create((object)vAsViewModel, isVm));
                }
            });

            var ret = changeWithValues.Subscribe(isVmWithLatestValue => {
                if (isVmWithLatestValue == null)
                {
                    return;
                }

                if (isVmWithLatestValue.Item2)
                {
                    Reflection.SetValueToPropertyChain(view, viewPropChain, isVmWithLatestValue.Item1, false);
                }
                else
                {
                    Reflection.SetValueToPropertyChain(view.ViewModel, vmPropChain, 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(ret);
        }