using System;
using System.ComponentModel;
using System.Linq.Expressions;
namespace DemoCode.Shared.Extensions
{
public static class ObservableExts
{
public static IObservable<IObservedChange<TSender, TValue>> ObservableForProperty<TSender, TValue>
(this TSender This, Expression<Func<TSender, TValue>> property, bool beforeChange = false)
where TSender : INotifyPropertyChanged
{
var observedChange = new ObservedChange<TSender, TValue>(This, property);
return new Observable<TSender, TValue>(observedChange);
}
public static IDisposable Subscribe<TSource>(this IObservable<TSource> source, Action<TSource> onNext)
where TSource : class
{
return new Unsubscriber<TSource>(source, onNext);
}
}
internal interface INotifySender
{
INotifyPropertyChanged Sender { get; }
string PropertyName { get; }
TSource GetSource<TSource>();
}
public interface IObservedChange<out TSender, out TValue>
{
TSender Sender { get; }
TValue Value { get; }
string PropertyName { get; }
}
public class ObservedChange<TSender, TValue> : IObservedChange<TSender, TValue>
{
private Expression<Func<TSender, TValue>> _property;
public ObservedChange(TSender sender, Expression<Func<TSender, TValue>> property)
{
Sender = sender;
var expression = property.Body as MemberExpression;
if (expression != null)
{
var member = expression.Member;
PropertyName = member.Name;
}
_property = property;
}
public TSender Sender { get; private set; }
public TValue Value { get { return (TValue)Sender.GetType().GetProperty(PropertyName).GetValue(Sender, null); } }
public string PropertyName { get; private set; }
}
public class Observable<TSender, TValue> : IObservable<IObservedChange<TSender, TValue>>, INotifySender
{
public Observable(IObservedChange<TSender, TValue> observedChange)
{
ObservedChange = observedChange;
}
public IObservedChange<TSender, TValue> ObservedChange { get; private set; }
public IDisposable Subscribe(IObserver<IObservedChange<TSender, TValue>> observer)
{
throw new NotImplementedException();
}
public INotifyPropertyChanged Sender
{
get { return ObservedChange.Sender as INotifyPropertyChanged; }
}
public string PropertyName
{
get { return ObservedChange.PropertyName; }
}
public TSource GetSource<TSource>()
{
return (TSource)ObservedChange;
}
}
internal class Unsubscriber<TSource> : IDisposable
where TSource : class
{
private IObservable<TSource> _source;
private readonly Action<TSource> _onNext;
private readonly INotifySender _notifySender;
public Unsubscriber(IObservable<TSource> source, Action<TSource> onNext)
{
_source = source;
_notifySender = source as INotifySender;
if (_notifySender != null && _notifySender.Sender != null)
{
_notifySender.Sender.PropertyChanged += SenderPropertyChanged;
}
_onNext = onNext;
}
void SenderPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (_onNext != null && e.PropertyName == _notifySender.PropertyName)
{
//_onNext(_onNext.Target as TSource);
System.Windows.Application.Current.Dispatcher
.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
(Action) (() => _onNext(_notifySender.GetSource<TSource>())));
}
}
public void Dispose()
{
_notifySender.Sender.PropertyChanged -= SenderPropertyChanged;
}
}
}