using System; using System.Windows; using System.Windows.Data; using Caliburn.Execution; using Caliburn.Messaging; using Caliburn.Metadata; using Caliburn.Services; namespace Caliburn.Actions { public abstract class ActionExecutor { protected readonly ActionInfo _actionInfo; protected readonly IUnboundMethod _unboundMethod; public ActionExecutor(ActionInfo actionInfo) { _actionInfo = actionInfo; _unboundMethod = UnboundMethodFactory.Create(actionInfo.MethodInfo); } public abstract void Execute(DependencyObject messageSource, ActionMessage message, object target); protected virtual void PerformRescue(object target, Exception exception) { if(!_actionInfo.PerformRescue(target, exception)) { if(!_actionInfo.Owner.PerformRescue(target, exception)) { throw new CaliburnException( string.Format("There was a problem executing {0} on {1}.", _actionInfo.Name, target.GetType().Name ), exception ); } } } protected virtual void BindReturnValue(ActionMessage message, DependencyObject messageSource, object result) { if(_actionInfo.MethodInfo.ReturnType != typeof(void)) { if(message.Return != null) { Parameter temp = new Parameter(); NameScope.SetNameScope(temp, message.NameScope); BindingOperations.SetBinding(temp, Parameter.ValueProperty, message.Return); temp.Value = result; BindingOperations.ClearBinding(temp, Parameter.ValueProperty); } else { PresenterBinding binding = DI.Resolve().GetBinding(messageSource); FrameworkElement element = binding.Target as FrameworkElement; if(element != null) { string returnName = _actionInfo.Name + "Result"; object returnElement = element.FindName(returnName); if(returnElement != null) { ElementDefaults defaults = DI.Resolve().GetDefaults(returnElement.GetType()); defaults.SetDefaultValue(returnElement, result); } } } } } protected virtual object[] DetermineParameters(ActionMessage message, DependencyObject messageSource) { object[] parameters = new object[_actionInfo.Parameters.Length]; if(message.Parameters.Count >= _actionInfo.Parameters.Length) { for(int i = 0; i < parameters.Length; i++) { parameters[i] = CoerceType( message.Parameters[i].Value, _actionInfo.Parameters[i].ParameterType ); } } else { PresenterBinding binding = DI.Resolve().GetBinding(messageSource); FrameworkElement element = binding.Target as FrameworkElement; if(element != null) { for(int i = 0; i < _actionInfo.Parameters.Length; i++) { DependencyObject dpo = element.FindName(_actionInfo.Parameters[i].Name) as DependencyObject; if(dpo != null) { ElementDefaults defaults = DI.Resolve().GetDefaults(dpo.GetType()); parameters[i] = CoerceType( defaults.GetDefaultValue(dpo), _actionInfo.Parameters[i].ParameterType ); } else { GetParametersFromDefaultOrFail(message, messageSource, parameters); break; } } } else GetParametersFromDefaultOrFail(message, messageSource, parameters); } return parameters; } protected virtual void GetParametersFromDefaultOrFail(ActionMessage message, DependencyObject messageSource, object[] parameters) { if(_actionInfo.Parameters.Length == 1) { ElementDefaults defaults = DI.Resolve().GetDefaults(messageSource.GetType()); if(defaults != null) { parameters[0] = CoerceType( defaults.GetDefaultValue(messageSource), _actionInfo.Parameters[0].ParameterType ); } else throw new CaliburnException("No default value was registered for " + messageSource.GetType().Name); } else { throw new CaliburnException( string.Format("Insuficient paramters supplied to action. {0} supplied, {1} required", message.Parameters.Count, _actionInfo.Parameters.Length ) ); } } protected virtual object CoerceType(object value, Type targetType) { if(value == null) return GetDefaultValue(targetType); if(targetType.IsAssignableFrom(value.GetType())) return value; else { try { return Convert.ChangeType(value, targetType); } catch { return GetDefaultValue(targetType); } } } protected virtual object GetDefaultValue(Type type) { if(type.IsClass) return null; else return Activator.CreateInstance(type); } } }