/// <summary> /// RaiseAndSetIfChanged fully implements a Setter for a read-write /// property on a ReactiveObject, making the assumption that the /// property has a backing field named "_NameOfProperty". To change this /// assumption, set RxApp.GetFieldNameForPropertyNameFunc. /// </summary> /// <param name="property">An Expression representing the property (i.e. /// 'x => x.SomeProperty'</param> /// <param name="newValue">The new value to set the property to, almost /// always the 'value' keyword.</param> /// <returns>The newly set value, normally discarded.</returns> public static TRet RaiseAndSetIfChanged <TObj, TRet>( this TObj This, Expression <Func <TObj, TRet> > property, TRet newValue) where TObj : ReactiveObject { Contract.Requires(This != null); Contract.Requires(property != null); FieldInfo field; string prop_name = Reflection.SimpleExpressionToPropertyName(property); field = Reflection.GetBackingFieldInfoForProperty <TObj>(prop_name); var field_val = field.GetValue(This); if (EqualityComparer <TRet> .Default.Equals((TRet)field_val, (TRet)newValue)) { return(newValue); } This.raisePropertyChanging(prop_name); field.SetValue(This, newValue); This.raisePropertyChanged(prop_name); return(newValue); }
public IReactiveBinding <TView, TViewModel, TProp> BindCommand <TView, TViewModel, TProp, TControl, TParam>( TViewModel viewModel, TView view, Expression <Func <TViewModel, TProp> > propertyName, Expression <Func <TView, TControl> > controlName, Func <TParam> withParameter, string toEvent = null) where TViewModel : class where TView : class, IViewFor <TViewModel> where TProp : ICommand { var ctlName = Reflection.SimpleExpressionToPropertyName(controlName); var viewPropGetter = Reflection.GetValueFetcherForProperty(typeof(TView), ctlName); IObservable <TProp> changed; IDisposable bindingDisposable = bindCommandInternal(viewModel, view, propertyName, viewPropGetter, Observable.Empty <object>(), toEvent, out changed, cmd => { var rc = cmd as IReactiveCommand; if (rc == null) { return(Legacy.ReactiveCommand.Create(x => cmd.CanExecute(x), _ => cmd.Execute(withParameter()))); } var ret = new ReactiveCommand(rc.CanExecuteObservable); ret.Subscribe(_ => rc.Execute(withParameter())); return(ret); }); return(new ReactiveBinding <TView, TViewModel, TProp>(view, viewModel, new string[] { ctlName }, new string[] { Reflection.SimpleExpressionToPropertyName(propertyName) }, changed, BindingDirection.OneWay, bindingDisposable)); }
/// <summary> /// Use this method in your ReactiveObject classes when creating custom /// properties where raiseAndSetIfChanged doesn't suffice. /// </summary> /// <param name="property">An Expression representing the property (i.e. /// 'x => x.SomeProperty'</param> public static void RaisePropertyChanged <TObj, TRet>( this TObj This, Expression <Func <TObj, TRet> > property) where TObj : ReactiveObject { var propName = Reflection.SimpleExpressionToPropertyName(property); This.raisePropertyChanged(propName); }
IDisposable bindCommandInternal <TView, TViewModel, TProp, TParam>( TViewModel viewModel, TView view, Expression <Func <TViewModel, TProp> > propertyName, Func <object, object> viewPropGetter, IObservable <TParam> withParameter, string toEvent, out IObservable <TProp> changed, Func <ICommand, ICommand> commandFixuper = null) where TViewModel : class where TView : class, IViewFor <TViewModel> where TProp : ICommand { var propName = Reflection.SimpleExpressionToPropertyName(propertyName); IDisposable disp = Disposable.Empty; changed = Reflection.ViewModelWhenAnyValue(viewModel, view, propertyName).Publish().RefCount(); var propSub = changed.Subscribe(x => { disp.Dispose(); if (x == null) { disp = Disposable.Empty; return; } var target = viewPropGetter(view); if (target == null) { this.Log().Error("Binding {0}.{1} => {2}.{1} failed because target is null", typeof(TViewModel).FullName, propName, view.GetType().FullName); disp = Disposable.Empty; } var cmd = commandFixuper != null ? commandFixuper(x) : x; if (toEvent != null) { disp = CreatesCommandBinding.BindCommandToObject(cmd, target, withParameter.Select(y => (object)y), toEvent); } else { disp = CreatesCommandBinding.BindCommandToObject(cmd, target, withParameter.Select(y => (object)y)); } }); return(Disposable.Create(() => { propSub.Dispose(); disp.Dispose(); })); }
public IReactiveBinding <TView, TViewModel, TProp> BindCommand <TView, TViewModel, TProp>( TViewModel viewModel, TView view, Expression <Func <TViewModel, TProp> > propertyName, string toEvent = null) where TViewModel : class where TView : class, IViewFor <TViewModel> where TProp : ICommand { var ctlName = Reflection.SimpleExpressionToPropertyName(propertyName); var viewPropGetter = Reflection.GetValueFetcherForProperty(typeof(TView), ctlName); IObservable <TProp> changed; IDisposable disp = bindCommandInternal(viewModel, view, propertyName, viewPropGetter, Observable.Empty <object>(), toEvent, out changed); return(new ReactiveBinding <TView, TViewModel, TProp>(view, viewModel, new string[] { ctlName }, new string[] { ctlName }, changed, BindingDirection.OneWay, disp)); }
/// <summary> /// Converts an Observable to an ObservableAsPropertyHelper and /// automatically provides the onChanged method to raise the property /// changed notification. The ToProperty method is semantically /// equivalent to this method and is often more convenient. /// </summary> /// <param name="observable">The Observable to base the property on.</param> /// <param name="property">An Expression representing the property (i.e. /// 'x => x.SomeProperty'</param> /// <param name="initialValue">The initial value of the property.</param> /// <param name="scheduler">The scheduler that the notifications will be /// provided on - this should normally be a Dispatcher-based scheduler /// (and is by default)</param> /// <returns>An initialized ObservableAsPropertyHelper; use this as the /// backing field for your property.</returns> public static ObservableAsPropertyHelper <TRet> ObservableToProperty <TObj, TRet>( this TObj This, IObservable <TRet> observable, Expression <Func <TObj, TRet> > property, TRet initialValue = default(TRet), IScheduler scheduler = null) where TObj : ReactiveObject { Contract.Requires(This != null); Contract.Requires(observable != null); Contract.Requires(property != null); string prop_name = Reflection.SimpleExpressionToPropertyName(property); var ret = new ObservableAsPropertyHelper <TRet>(observable, _ => This.raisePropertyChanged(prop_name), initialValue, scheduler); LogHost.Default.Debug("OAPH {0:X} is for {1}", ret, prop_name); return(ret); }
public IReactiveBinding <TView, TViewModel, TProp> BindCommand <TView, TViewModel, TProp, TControl, TParam>( TViewModel viewModel, TView view, Expression <Func <TViewModel, TProp> > propertyName, Expression <Func <TView, TControl> > controlName, IObservable <TParam> withParameter, string toEvent = null) where TViewModel : class where TView : class, IViewFor <TViewModel> where TProp : ICommand { var ctlName = Reflection.SimpleExpressionToPropertyName(controlName); var viewPropGetter = Reflection.GetValueFetcherForProperty(typeof(TView), ctlName); IObservable <TProp> changed; IDisposable bindingDisposable = bindCommandInternal(viewModel, view, propertyName, viewPropGetter, withParameter, toEvent, out changed); return(new ReactiveBinding <TView, TViewModel, TProp>(view, viewModel, new string[] { ctlName }, Reflection.ExpressionToPropertyNames(propertyName), changed, BindingDirection.OneWay, bindingDisposable)); }
/// <summary> /// RaiseAndSetIfChanged fully implements a Setter for a read-write /// property on a ReactiveObject, making the assumption that the /// property has a backing field named "_NameOfProperty". To change this /// assumption, set RxApp.GetFieldNameForPropertyNameFunc. This /// overload is intended for Silverlight and WP7 where reflection /// cannot access the private backing field. /// </summary> /// <param name="property">An Expression representing the property (i.e. /// 'x => x.SomeProperty'</param> /// <param name="backingField">A Reference to the backing field for this /// property.</param> /// <param name="newValue">The new value to set the property to, almost /// always the 'value' keyword.</param> /// <returns>The newly set value, normally discarded.</returns> public static TRet RaiseAndSetIfChanged <TObj, TRet>( this TObj This, Expression <Func <TObj, TRet> > property, ref TRet backingField, TRet newValue) where TObj : ReactiveObject { Contract.Requires(This != null); Contract.Requires(property != null); if (EqualityComparer <TRet> .Default.Equals(backingField, newValue)) { return(newValue); } string prop_name = Reflection.SimpleExpressionToPropertyName(property); This.raisePropertyChanging(prop_name); backingField = newValue; This.raisePropertyChanged(prop_name); return(newValue); }
/// <summary> /// Converts an Observable to an ObservableAsPropertyHelper and /// automatically provides the onChanged method to raise the property /// changed notification. /// </summary> /// <param name="source">The ReactiveObject that has the property</param> /// <param name="property">An Expression representing the property (i.e. /// 'x => x.SomeProperty'</param> /// <param name="initialValue">The initial value of the property.</param> /// <param name="scheduler">The scheduler that the notifications will be /// provided on - this should normally be a Dispatcher-based scheduler /// (and is by default)</param> /// <returns>An initialized ObservableAsPropertyHelper; use this as the /// backing field for your property.</returns> public static ObservableAsPropertyHelper <TRet> ToProperty <TObj, TRet>( this IObservable <TRet> This, TObj source, Expression <Func <TObj, TRet> > property, TRet initialValue = default(TRet), IScheduler scheduler = null, bool setViaReflection = true) where TObj : ReactiveObject { var ret = source.ObservableToProperty(This, property, initialValue, scheduler); string propName = Reflection.SimpleExpressionToPropertyName(property); if (setViaReflection) { var fi = Reflection.GetBackingFieldInfoForProperty <TObj>(propName, true); if (fi != null) { fi.SetValue(source, ret); } } return(ret); }
/// <summary> /// RaisePropertyChanged is a helper method intended for test / mock /// scenarios to manually fake a property change. /// </summary> /// <param name="target">The ReactiveObject to invoke /// raisePropertyChanging on.</param> /// <param name="property">The property that will be faking a change.</param> public static void RaisePropertyChanged <TSender, TValue>(TSender target, Expression <Func <TSender, TValue> > property) where TSender : ReactiveObject { RaisePropertyChanged(target, Reflection.SimpleExpressionToPropertyName(property)); }