Skip to content

Instantly share code, notes, and snippets.

@devknoll
Last active March 11, 2016 16:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save devknoll/4407479 to your computer and use it in GitHub Desktop.
Save devknoll/4407479 to your computer and use it in GitHub Desktop.
Convention for binding Caliburn.Micro action guard methods (i.e. CanExecute) to Rx IObservable<bool>.
var basePrepareContext = ActionMessage.PrepareContext;
ActionMessage.PrepareContext = (context) =>
{
ActionMessage.SetMethodBinding(context);
if (context.Target == null || context.Method == null)
return;
var guardName = "Can" + context.Method.Name;
var targetType = context.Target.GetType();
var guard = targetType.GetMethod("get_" + guardName);
if (guard == null || !typeof(IObservable<bool>).IsAssignableFrom(guard.ReturnType))
{
basePrepareContext(context);
return;
}
var inpc = context.Target as INotifyPropertyChanged;
if (inpc == null)
return;
var canExecute = false;
var subscription = default(IDisposable);
var setObservable = default(System.Action<IObservable<bool>>);
setObservable = (newObservable) =>
{
if (subscription != null)
{
subscription.Dispose();
subscription = null;
}
if (newObservable != null)
{
subscription = newObservable.DistinctUntilChanged().SubscribeOnDispatcher().Subscribe(x =>
{
canExecute = x;
context.Message.UpdateAvailability();
});
}
else
{
canExecute = false;
context.Message.UpdateAvailability();
}
};
var handler = default(PropertyChangedEventHandler);
handler = (sender, e) =>
{
if (string.IsNullOrEmpty(e.PropertyName) || e.PropertyName == guardName)
{
if (context.Message == null)
{
inpc.PropertyChanged -= handler;
setObservable(null);
return;
}
setObservable(guard.Invoke(context.Target, null) as IObservable<bool>);
}
};
setObservable(guard.Invoke(context.Target, null) as IObservable<bool>);
context.CanExecute = () => canExecute;
inpc.PropertyChanged += handler;
context.Disposing += delegate { inpc.PropertyChanged -= handler; };
context.Message.Detaching += delegate { inpc.PropertyChanged -= handler; };
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment