Skip to content

Instantly share code, notes, and snippets.

@distantcam
Created February 19, 2013 02:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save distantcam/4982662 to your computer and use it in GitHub Desktop.
Save distantcam/4982662 to your computer and use it in GitHub Desktop.
RxUI Light
using System;
using System.Reactive;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Windows.Input;
public class RxCommand : ICommand, IObservable<object>, IDisposable
{
private readonly ISubject<bool> canExecuteSubject;
private readonly ISubject<object> executeSubject;
private readonly IDisposable inner;
private bool canExecuteLatest = true;
public RxCommand(IObservable<bool> canExecute = null)
{
canExecute = canExecute ?? Observable.Return(true).Concat(Observable.Never<bool>());
canExecute = canExecute.ObserveOnDispatcher();
canExecuteSubject = new Subject<bool>();
inner = canExecute.Subscribe(OnExecuteChanged);
executeSubject = new Subject<object>();
}
public event EventHandler CanExecuteChanged;
public IObservable<bool> CanExecuteObservable
{
get { return canExecuteSubject.ObserveOnDispatcher().DistinctUntilChanged(); }
}
public bool CanExecute(object parameter)
{
return canExecuteLatest;
}
public void Execute(object parameter)
{
executeSubject.OnNext(parameter);
}
public IDisposable Subscribe(IObserver<object> observer)
{
return executeSubject.ObserveOnDispatcher().Subscribe(
Observer.Create<object>(
x => LogOnError(() => observer.OnNext(x)),
ex => LogOnError(() => observer.OnError(ex)),
() => LogOnError(observer.OnCompleted)));
}
public void Dispose()
{
if (inner != null)
inner.Dispose();
}
private static void LogOnError(Action action)
{
try
{
action();
}
catch
{
// Log
}
}
private void OnExecuteChanged(bool obj)
{
canExecuteLatest = obj;
canExecuteSubject.OnNext(obj);
var handler = CanExecuteChanged;
if (handler != null)
handler(this, EventArgs.Empty);
}
}
using System;
using System.ComponentModel;
using System.Reactive.Disposables;
using System.Reactive.Subjects;
using System.Threading;
public class RxObject : INotifyPropertyChanged, INotifyPropertyChanging
{
private readonly Subject<ObservedChange> changedSubject;
private readonly Subject<ObservedChange> changingSubject;
private long changeNotificationsSuppressed = 0;
protected RxObject()
{
changingSubject = new Subject<ObservedChange>();
changedSubject = new Subject<ObservedChange>();
}
public event PropertyChangedEventHandler PropertyChanged;
public event PropertyChangingEventHandler PropertyChanging;
public IObservable<ObservedChange> Changing { get { return changingSubject; } }
public IObservable<ObservedChange> Changed { get { return changedSubject; } }
public IDisposable SuppressChangeNotifications()
{
Interlocked.Increment(ref changeNotificationsSuppressed);
return Disposable.Create(() =>
Interlocked.Decrement(ref changeNotificationsSuppressed));
}
protected void OnPropertyChanged(string propertyName)
{
if (!ChangeNotificationsEnabled())
return;
var handler = this.PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
try
{
changedSubject.OnNext(new ObservedChange(this, propertyName));
}
catch (Exception ex)
{
changedSubject.OnError(ex);
}
}
protected void OnPropertyChanging(string propertyName)
{
if (!ChangeNotificationsEnabled())
return;
var handler = this.PropertyChanging;
if (handler != null)
handler(this, new PropertyChangingEventArgs(propertyName));
try
{
changingSubject.OnNext(new ObservedChange(this, propertyName));
}
catch (Exception ex)
{
changingSubject.OnError(ex);
}
}
private bool ChangeNotificationsEnabled()
{
return Interlocked.Read(ref changeNotificationsSuppressed) == 0;
}
public struct ObservedChange
{
public readonly string PropertyName;
public readonly object Sender;
public ObservedChange(object sender, string propertyName)
{
Sender = sender;
PropertyName = propertyName;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment