string getPropertyValidationError(string propName) { PropertyExtraInfo pei; lock (allValidatedProperties) { if (!allValidatedProperties.Get(this.GetType()).TryGetValue(propName, out pei)) { return(null); } } foreach (var v in pei.ValidationAttributes) { try { var ctx = new ValidationContext(this, null, null) { MemberName = propName }; var getter = Reflection.GetValueFetcherForProperty(pei.Type, propName); v.Validate(getter(this), ctx); } catch (Exception ex) { this.Log().Info("{0:X}.{1} failed validation: {2}", this.GetHashCode(), propName, ex.Message); return(ex.Message); } } return(null); }
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)); }
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)); }
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)); }
static void subscribeToExpressionChain <TSender, TValue>( TSender origSource, string origPath, object source, LinkedListNode <string> propertyNames, LinkedListNode <IDisposable> subscriptions, bool beforeChange, Subject <IObservedChange <TSender, TValue> > subject ) { var current = propertyNames; var currentSub = subscriptions; object currentObj = source; ObservedChange <TSender, TValue> obsCh; while (current.Next != null) { Func <object, object> getter = null; if (currentObj != null) { getter = Reflection.GetValueFetcherForProperty(currentObj.GetType(), current.Value); if (getter == null) { subscriptions.List.Where(x => x != null).ForEach(x => x.Dispose()); throw new ArgumentException(String.Format("Property '{0}' does not exist in expression", current.Value)); } var capture = new { current, currentObj, getter, currentSub }; var toDispose = new IDisposable[2]; var valGetter = new ObservedChange <object, TValue>() { Sender = capture.currentObj, PropertyName = buildPropPathFromNodePtr(capture.current), Value = default(TValue), }; TValue prevVal = default(TValue); bool prevValSet = valGetter.TryGetValue(out prevVal); toDispose[0] = notifyForProperty(currentObj, capture.current.Value, true).Subscribe(x => { prevValSet = valGetter.TryGetValue(out prevVal); }); toDispose[1] = notifyForProperty(currentObj, capture.current.Value, false).Subscribe(x => { subscribeToExpressionChain(origSource, origPath, capture.getter(capture.currentObj), capture.current.Next, capture.currentSub.Next, beforeChange, subject); TValue newVal; if (!valGetter.TryGetValue(out newVal)) { return; } if (prevValSet && EqualityComparer <TValue> .Default.Equals(prevVal, newVal)) { return; } obsCh = new ObservedChange <TSender, TValue>() { Sender = origSource, PropertyName = origPath, Value = default(TValue), }; TValue obsChVal; if (obsCh.TryGetValue(out obsChVal)) { obsCh.Value = obsChVal; subject.OnNext(obsCh); } }); currentSub.Value = Disposable.Create(() => { toDispose[0].Dispose(); toDispose[1].Dispose(); }); } current = current.Next; currentSub = currentSub.Next; currentObj = getter != null?getter(currentObj) : null; } if (currentSub.Value != null) { currentSub.Value.Dispose(); } if (currentObj == null) { return; } var propName = current.Value; var finalGetter = Reflection.GetValueFetcherForProperty(currentObj.GetType(), current.Value); currentSub.Value = notifyForProperty(currentObj, propName, beforeChange).Subscribe(x => { obsCh = new ObservedChange <TSender, TValue>() { Sender = origSource, PropertyName = origPath, Value = (TValue)finalGetter(currentObj), }; subject.OnNext(obsCh); }); }