/// <summary> /// Sets up a new reaction pipeline on a component that implements INotifyPropertyChanged. This is /// /// This method is provided for interop on platforms that dont support the ExpandoObject (dynamic) ie. Xamarin.iOS /// </summary> /// <typeparam name="T"></typeparam> /// <param name="source"></param> /// <param name="observeInitial">If the subscription will be alerted as soon as its made, no property change is required</param> /// <param name="scheduler"></param> /// <param name="properties">The properties to watch for changes to</param> /// <returns>A dictionary with the propertName as the key, and property value which u will need to cast to whatever type they are supposed to be</returns> public static IObservable <Dictionary <string, object> > OnReaction <T>(this T source, bool observeInitial, IScheduler scheduler, params Expression <Func <T, object> >[] properties) where T : INotifyPropertyChanged { return(RxObservable.DfrCreate <Dictionary <string, object> >(o => { try { var propertyNames = new Dictionary <string, Func <T, object> >(); Func <Dictionary <string, object> > GetValues = () => { var d = new Dictionary <string, object>(); foreach (var p in propertyNames) { d[p.Key] = p.Value.Invoke(source); } return d; }; foreach (var property in properties) { propertyNames.Add(property.GetPropertyInfo().Name, property.Compile()); } var sub = IObservableExtensions .FromPropertyChanged <PropertyChangedEventHandler, PropertyChangedEventArgs>( handler => handler.Invoke, h => source.PropertyChanged += h, h => source.PropertyChanged -= h) .Where(e => propertyNames.ContainsKey(e.EventArgs.PropertyName)) .Select(e => GetValues()); if (observeInitial) { sub = sub.StartWith(GetValues()); } return sub.Subscribe(o); } catch (Exception e) { o.OnError(e); return Disposable.Empty; } }) .ObserveOn(scheduler) .SubscribeOn(scheduler)); }
/// <summary> /// Sets up a new reaction pipeline on a component that implements INotifyPropertyChanged. Typically this is followed by an action to be taken /// when TStuff occours /// /// advanced: its a simple fluent wrapper for Input.ObserveOn /// </summary> /// <typeparam name="TStuff"></typeparam> /// <param name="stream">An observable you want to use as a quasi reaction component</param> /// <param name="scheduler">The scheduler tha the pipeline will use for work. Defaults to OnReactionScheduler</param> /// <param name="properties">The properties too watch for changes. The properties can then be referenced by name on the returned dynamic object</param> /// <returns>A dynamic object with the properties and their values attached. Reference them by the same name</returns> public static IObservable <dynamic> OnReactionTo <T>(this T source, IScheduler scheduler, params Expression <Func <T, object> >[] properties) where T : INotifyPropertyChanged { return(Observable.Create <dynamic>(o => { try { var propertyNames = new Dictionary <string, Func <T, dynamic> >(); foreach (var property in properties) { propertyNames.Add(property.GetPropertyInfo().Name, property.Compile()); } return IObservableExtensions .FromPropertyChanged <PropertyChangedEventHandler, PropertyChangedEventArgs>( handler => handler.Invoke, h => source.PropertyChanged += h, h => source.PropertyChanged -= h) .ObserveOn(scheduler) .Where(e => propertyNames.ContainsKey(e.EventArgs.PropertyName)) .Select(e => { dynamic d = new ExpandoObject(); foreach (var p in propertyNames) { ((IDictionary <string, object>)d)[p.Key] = p.Value.Invoke(source); } return d; }) .Subscribe(o); } catch (Exception e) { o.OnError(e); return Disposable.Empty; } })); }