#if XFORMS namespace Caliburn.Micro.Core.Xamarin.Forms #else namespace Caliburn.Micro #endif { using System; using System.Globalization; using System.Linq; using System.Reflection; using System.Collections.Generic; #if !SILVERLIGHT using System.ComponentModel; #endif /// /// A service that is capable of properly binding values to a method's parameters and creating instances of . /// public static class MessageBinder { /// /// The special parameter values recognized by the message binder along with their resolvers. /// Parameter names are case insensitive so the specified names are unique and can be used with different case variations /// public static readonly Dictionary> SpecialValues = new Dictionary>(StringComparer.OrdinalIgnoreCase) { {"$eventargs", c => c.EventArgs}, #if XFORMS {"$datacontext", c => c.Source.BindingContext}, {"$bindingcontext", c => c.Source.BindingContext}, #else {"$datacontext", c => c.Source.DataContext}, #endif {"$source", c => c.Source}, {"$executioncontext", c => c}, {"$view", c => c.View} }; /// /// Custom converters used by the framework registered by destination type for which they will be selected. /// The converter is passed the existing value to convert and a "context" object. /// public static readonly Dictionary> CustomConverters = new Dictionary> { { typeof (DateTime), (value, context) => { DateTime result; DateTime.TryParse(value.ToString(), out result); return result; } } }; /// /// Determines the parameters that a method should be invoked with. /// /// The action execution context. /// The parameters required to complete the invocation. /// The actual parameter values. public static object[] DetermineParameters(ActionExecutionContext context, ParameterInfo[] requiredParameters) { var providedValues = context.Message.Parameters.OfType().Select(x => x.Value).ToArray(); var finalValues = new object[requiredParameters.Length]; for (int i = 0; i < requiredParameters.Length; i++) { var parameterType = requiredParameters[i].ParameterType; var parameterValue = providedValues[i]; var parameterAsString = parameterValue as string; if (parameterAsString != null) finalValues[i] = CoerceValue(parameterType, EvaluateParameter(parameterAsString, parameterType, context), context); else finalValues[i] = CoerceValue(parameterType, parameterValue, context); } return finalValues; } /// /// Transforms the textual parameter into the actual parameter. /// public static Func EvaluateParameter = (text, parameterType, context) => { Func resolver; return SpecialValues.TryGetValue(text, out resolver) ? resolver(context) : text; }; /// /// Coerces the provided value to the destination type. /// /// The destination type. /// The provided value. /// An optional context value which can be used during conversion. /// The coerced value. public static object CoerceValue(Type destinationType, object providedValue, object context) { if (providedValue == null) { return GetDefaultValue(destinationType); } var providedType = providedValue.GetType(); if (destinationType.IsAssignableFrom(providedType)) { return providedValue; } if (CustomConverters.ContainsKey(destinationType)) { return CustomConverters[destinationType](providedValue, context); } try { #if !WinRT && !XFORMS var converter = TypeDescriptor.GetConverter(destinationType); if (converter.CanConvertFrom(providedType)) { return converter.ConvertFrom(providedValue); } converter = TypeDescriptor.GetConverter(providedType); if (converter.CanConvertTo(destinationType)) { return converter.ConvertTo(providedValue, destinationType); } #endif #if WinRT || XFORMS if (destinationType.GetTypeInfo().IsEnum) { #else if (destinationType.IsEnum) { #endif var stringValue = providedValue as string; if (stringValue != null) { return Enum.Parse(destinationType, stringValue, true); } return Enum.ToObject(destinationType, providedValue); } if (typeof (Guid).IsAssignableFrom(destinationType)) { var stringValue = providedValue as string; if (stringValue != null) { return new Guid(stringValue); } } } catch { return GetDefaultValue(destinationType); } try { return Convert.ChangeType(providedValue, destinationType, CultureInfo.CurrentCulture); } catch { return GetDefaultValue(destinationType); } } /// /// Gets the default value for a type. /// /// The type. /// The default value. public static object GetDefaultValue(Type type) { #if WinRT || XFORMS var typeInfo = type.GetTypeInfo(); return typeInfo.IsClass || typeInfo.IsInterface ? null : System.Activator.CreateInstance(type); #else return type.IsClass || type.IsInterface ? null : Activator.CreateInstance(type); #endif } } }