Xcalllibur
unread,Apr 25, 2011, 10:51:48 AM4/25/11Sign in to reply to author
Sign in to forward
You do not have permission to delete messages in this group
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to ReactiveUI mailing list
Can you add a generic version of ReactiveCommand to the framework.
Coming from nRoute background i miss this because it makes it easier
to process the parameters passed to the command. The one i am
currently using looks like the following. Note that it does not
implement IReactiveCommand because having to implement
IObservable<object> causes ambiguity when i also have to implement
IObservable<T>. If IReactiveCommand was changed to be generic this
wouldnt be an issue. Since the interface is not explicitly used
anywhere in the framework it doesnt currently cause an issue:
public class ReactiveCommand<T> : ICommand, IEnableLogger,
IObservable<T>
{
private readonly Func<T, bool> canExecuteExplicitFunc;
private ObservableAsPropertyHelper<bool> canExecuteLatest;
private IScheduler scheduler;
private Subject<T> executeSubject;
public ReactiveCommand(IObservable<bool> canExecute = null,
IScheduler scheduler = null)
{
canExecute = canExecute ??
Observable.Return(true).Concat(Observable.Never<bool>());
this.Initialise(scheduler);
canExecute.Subscribe(this.CanExecuteSubject.OnNext);
}
protected ReactiveCommand(Func<T, bool> canExecute, IScheduler
scheduler = null)
{
this.canExecuteExplicitFunc = canExecute;
this.Initialise(scheduler);
}
public event EventHandler CanExecuteChanged;
protected Subject<bool> CanExecuteSubject
{
get;
private set;
}
public IObservable<bool> CanExecuteObservable
{
get
{
return this.CanExecuteSubject.DistinctUntilChanged();
}
}
public virtual bool CanExecute(T parameter)
{
if (this.canExecuteExplicitFunc != null)
{
bool ret = this.canExecuteExplicitFunc(parameter);
this.CanExecuteSubject.OnNext(ret);
return ret;
}
return this.canExecuteLatest.Value;
}
public void Execute(T parameter)
{
this.Log().InfoFormat("{0:X}: Executed",
this.GetHashCode());
this.executeSubject.OnNext(parameter);
}
public IDisposable Subscribe(IObserver<T> observer)
{
return
this.executeSubject.ObserveOn(this.scheduler).Subscribe(observer);
}
public static ReactiveCommand<T> Create(IObservable<bool>
canExecute = null, Action<T> onNext = null, IScheduler scheduler =
null)
{
var command = new ReactiveCommand<T>(canExecute,
scheduler);
if (onNext != null)
{
command.Subscribe(onNext);
}
return command;
}
protected virtual T ParseParameter(object parameter, Type
type)
{
if (parameter == null)
{
return default(T);
}
if (type.IsEnum)
{
return (T)Enum.Parse(type,
Convert.ToString(parameter), true);
}
if (type.IsValueType)
{
return (T)Convert.ChangeType(parameter, type, null);
}
return (T)parameter;
}
protected void CheckParameterType(object parameter)
{
if (parameter == null)
{
return;
}
if (typeof(T).IsValueType)
{
return;
}
if (!typeof(T).IsAssignableFrom(parameter.GetType()))
{
var message =
String.Format(CultureInfo.CurrentCulture,
Messages.CommandTypeUnexpected, this.GetType().FullName,
typeof(T).FullName);
throw new ArgumentException(message, "parameter");
}
}
private void Initialise(IScheduler scheduler)
{
this.scheduler = scheduler ?? RxApp.DeferredScheduler;
this.CanExecuteSubject = new Subject<bool>();
this.canExecuteLatest = new
ObservableAsPropertyHelper<bool>
(
this.CanExecuteSubject,
b =>
{
if (this.CanExecuteChanged != null)
{
this.CanExecuteChanged(this, EventArgs.Empty);
}
},
true,
this.scheduler
);
this.executeSubject = new Subject<T>();
}
bool ICommand.CanExecute(object parameter)
{
this.CheckParameterType(parameter);
return this.CanExecute(this.ParseParameter(parameter,
typeof(T)));
}
void ICommand.Execute(object parameter)
{
this.CheckParameterType(parameter);
this.Execute(this.ParseParameter(parameter, typeof(T)));
}
}