| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328 | 
							- #if XFORMS
 
- namespace Caliburn.Micro.Core.Xamarin.Forms
 
- #else
 
- namespace Caliburn.Micro
 
- #endif
 
- {
 
-     using System;
 
-     using System.Linq;
 
-     using System.Collections.Generic;
 
-     using System.Reflection;
 
-     using System.Threading.Tasks;
 
- #if XFORMS
 
-     using UIElement = global::Xamarin.Forms.Element;
 
-     using FrameworkElement = global::Xamarin.Forms.VisualElement;
 
-     using DependencyProperty = global::Xamarin.Forms.BindableProperty;
 
-     using DependencyObject = global::Xamarin.Forms.BindableObject;
 
- #elif WinRT81
 
-     using Windows.UI.Xaml;
 
-     using Microsoft.Xaml.Interactivity;
 
- #else
 
-     using System.Windows;
 
-     using System.Windows.Interactivity;
 
-     using Caliburn.Micro.Core;
 
- #endif
 
- #if WINDOWS_PHONE
 
-     using Microsoft.Phone.Controls;
 
- #endif
 
-     /// <summary>
 
-     /// Binds a view to a view model.
 
-     /// </summary>
 
-     public static class ViewModelBinder {
 
-         const string AsyncSuffix = "Async";
 
-         static readonly ILog Log = LogManager.GetLog(typeof(ViewModelBinder));
 
-         /// <summary>
 
-         /// Gets or sets a value indicating whether to apply conventions by default.
 
-         /// </summary>
 
-         /// <value>
 
-         /// 	<c>true</c> if conventions should be applied by default; otherwise, <c>false</c>.
 
-         /// </value>
 
-         public static bool ApplyConventionsByDefault = true;
 
-         /// <summary>
 
-         /// Indicates whether or not the conventions have already been applied to the view.
 
-         /// </summary>
 
-         public static readonly DependencyProperty ConventionsAppliedProperty =
 
-             DependencyPropertyHelper.RegisterAttached(
 
-                 "ConventionsApplied",
 
-                 typeof(bool),
 
-                 typeof(ViewModelBinder),
 
-                 false
 
-                 );
 
-         /// <summary>
 
-         /// Determines whether a view should have conventions applied to it.
 
-         /// </summary>
 
-         /// <param name="view">The view to check.</param>
 
-         /// <returns>Whether or not conventions should be applied to the view.</returns>
 
-         public static bool ShouldApplyConventions(FrameworkElement view) {
 
-             var overriden = View.GetApplyConventions(view);
 
-             return overriden.GetValueOrDefault(ApplyConventionsByDefault);
 
-         }
 
-         /// <summary>
 
-         /// Creates data bindings on the view's controls based on the provided properties.
 
-         /// </summary>
 
-         /// <remarks>Parameters include named Elements to search through and the type of view model to determine conventions for. Returns unmatched elements.</remarks>
 
-         public static Func<IEnumerable<FrameworkElement>, Type, IEnumerable<FrameworkElement>> BindProperties = (namedElements, viewModelType) => {
 
-             var unmatchedElements = new List<FrameworkElement>();
 
- #if !XFORMS
 
-             foreach (var element in namedElements) {
 
-                 var cleanName = element.Name.Trim('_');
 
-                 var parts = cleanName.Split(new[] { '_' }, StringSplitOptions.RemoveEmptyEntries);
 
-                 var property = viewModelType.GetPropertyCaseInsensitive(parts[0]);
 
-                 var interpretedViewModelType = viewModelType;
 
-                 for (int i = 1; i < parts.Length && property != null; i++) {
 
-                     interpretedViewModelType = property.PropertyType;
 
-                     property = interpretedViewModelType.GetPropertyCaseInsensitive(parts[i]);
 
-                 }
 
-                 if (property == null) {
 
-                     unmatchedElements.Add(element);
 
-                     Log.Info("Binding Convention Not Applied: Element {0} did not match a property.", element.Name);
 
-                     continue;
 
-                 }
 
-                 var convention = ConventionManager.GetElementConvention(element.GetType());
 
-                 if (convention == null) {
 
-                     unmatchedElements.Add(element);
 
-                     Log.Warn("Binding Convention Not Applied: No conventions configured for {0}.", element.GetType());
 
-                     continue;
 
-                 }
 
-                 var applied = convention.ApplyBinding(
 
-                     interpretedViewModelType,
 
-                     cleanName.Replace('_', '.'),
 
-                     property,
 
-                     element,
 
-                     convention
 
-                     );
 
-                 if (applied) {
 
-                     Log.Info("Binding Convention Applied: Element {0}.", element.Name);
 
-                 }
 
-                 else {
 
-                     Log.Info("Binding Convention Not Applied: Element {0} has existing binding.", element.Name);
 
-                     unmatchedElements.Add(element);
 
-                 }
 
-             }
 
- #endif
 
-             return unmatchedElements;
 
-         };
 
-         /// <summary>
 
-         /// Attaches instances of <see cref="ActionMessage"/> to the view's controls based on the provided methods.
 
-         /// </summary>
 
-         /// <remarks>Parameters include the named elements to search through and the type of view model to determine conventions for. Returns unmatched elements.</remarks>
 
-         public static Func<IEnumerable<FrameworkElement>, Type, IEnumerable<FrameworkElement>> BindActions = (namedElements, viewModelType) => {
 
-             var unmatchedElements = namedElements.ToList();
 
- #if !XFORMS
 
- #if WinRT || XFORMS
 
-             var methods = viewModelType.GetRuntimeMethods();
 
- #else
 
-             var methods = viewModelType.GetMethods();
 
- #endif
 
-             
 
-             foreach (var method in methods) {
 
-                 var foundControl = unmatchedElements.FindName(method.Name);
 
-                 if (foundControl == null && IsAsyncMethod(method)) {
 
-                     var methodNameWithoutAsyncSuffix = method.Name.Substring(0, method.Name.Length - AsyncSuffix.Length);
 
-                     foundControl = unmatchedElements.FindName(methodNameWithoutAsyncSuffix);
 
-                 }
 
-                 if(foundControl == null) {
 
-                     Log.Info("Action Convention Not Applied: No actionable element for {0}.", method.Name);
 
-                     continue;
 
-                 }
 
-                 unmatchedElements.Remove(foundControl);
 
- #if WinRT81
 
-                 var triggers = Interaction.GetBehaviors(foundControl);
 
-                 if (triggers != null && triggers.Count > 0)
 
-                 {
 
-                     Log.Info("Action Convention Not Applied: Interaction.Triggers already set on {0}.", foundControl.Name);
 
-                     continue;
 
-                 }
 
- #endif
 
-                 var message = method.Name;
 
-                 var parameters = method.GetParameters();
 
-                 if (parameters.Length > 0) {
 
-                     message += "(";
 
-                     foreach (var parameter in parameters) {
 
-                         var paramName = parameter.Name;
 
-                         var specialValue = "$" + paramName.ToLower();
 
-                         if (MessageBinder.SpecialValues.ContainsKey(specialValue))
 
-                             paramName = specialValue;
 
-                         message += paramName + ",";
 
-                     }
 
-                     message = message.Remove(message.Length - 1, 1);
 
-                     message += ")";
 
-                 }
 
-                 Log.Info("Action Convention Applied: Action {0} on element {1}.", method.Name, message);
 
-                 Message.SetAttach(foundControl, message);
 
-             }
 
- #endif
 
-             return unmatchedElements;
 
-         };
 
-         static bool IsAsyncMethod(MethodInfo method) {
 
-             return typeof(Task).IsAssignableFrom(method.ReturnType) &&
 
-                    method.Name.EndsWith(AsyncSuffix, StringComparison.OrdinalIgnoreCase);
 
-         }
 
-         /// <summary>
 
-         /// Allows the developer to add custom handling of named elements which were not matched by any default conventions.
 
-         /// </summary>
 
-         public static Action<IEnumerable<FrameworkElement>, Type> HandleUnmatchedElements = (elements, viewModelType) => { };
 
-         /// <summary>
 
-         /// Binds the specified viewModel to the view.
 
-         /// </summary>
 
-         ///<remarks>Passes the the view model, view and creation context (or null for default) to use in applying binding.</remarks>
 
-         public static Action<object, DependencyObject, object> Bind = (viewModel, view, context) => {
 
- #if !WinRT && !XFORMS
 
-             // when using d:DesignInstance, Blend tries to assign the DesignInstanceExtension class as the DataContext,
 
-             // so here we get the actual ViewModel which is in the Instance property of DesignInstanceExtension
 
-             if (View.InDesignMode) {
 
-                 var vmType = viewModel.GetType();
 
-                 if (vmType.FullName == "Microsoft.Expression.DesignModel.InstanceBuilders.DesignInstanceExtension") {
 
-                     var propInfo = vmType.GetProperty("Instance", BindingFlags.Instance | BindingFlags.NonPublic);
 
-                     viewModel = propInfo.GetValue(viewModel, null);
 
-                 }
 
-             }
 
- #endif
 
-             Log.Info("Binding {0} and {1}.", view, viewModel);
 
- #if XFORMS
 
-             var noContext = Caliburn.Micro.Xamarin.Forms.Bind.NoContextProperty;
 
- #else
 
-             var noContext = Caliburn.Micro.Bind.NoContextProperty;
 
- #endif
 
-             if ((bool)view.GetValue(noContext)) {
 
-                 Action.SetTargetWithoutContext(view, viewModel);
 
-             }
 
-             else {
 
-                 Action.SetTarget(view, viewModel);
 
-             }
 
-             var viewAware = viewModel as IViewAware;
 
-             if (viewAware != null) {
 
-                 Log.Info("Attaching {0} to {1}.", view, viewAware);
 
-                 viewAware.AttachView(view, context);
 
-             }
 
-             if ((bool)view.GetValue(ConventionsAppliedProperty)) {
 
-                 return;
 
-             }
 
-             var element = View.GetFirstNonGeneratedView(view) as FrameworkElement;
 
-             if (element == null) {
 
-                 return;
 
-             }
 
- #if WINDOWS_PHONE
 
-             BindAppBar(view);
 
- #endif
 
-             if (!ShouldApplyConventions(element)) {
 
-                 Log.Info("Skipping conventions for {0} and {1}.", element, viewModel);
 
- #if WINDOWS_PHONE
 
-                 view.SetValue(ConventionsAppliedProperty, true); // we always apply the AppBar conventions
 
- #endif
 
-                 return;
 
-             }
 
-             var viewModelType = viewModel.GetType();
 
- #if SL5 || NET45
 
-             var viewModelTypeProvider = viewModel as ICustomTypeProvider;
 
-             if (viewModelTypeProvider != null) {
 
-                 viewModelType = viewModelTypeProvider.GetCustomType();
 
-             }
 
- #endif
 
- #if XFORMS
 
-             IEnumerable<FrameworkElement> namedElements = new List<FrameworkElement>();
 
- #else
 
-             var namedElements = BindingScope.GetNamedElements(element);
 
- #endif
 
- #if SILVERLIGHT
 
-             namedElements.Apply(x => x.SetValue(
 
-                 View.IsLoadedProperty,
 
-                 element.GetValue(View.IsLoadedProperty))
 
-                 );
 
- #endif
 
-             namedElements = BindActions(namedElements, viewModelType);
 
-             namedElements = BindProperties(namedElements, viewModelType);
 
-             HandleUnmatchedElements(namedElements, viewModelType);
 
-             view.SetValue(ConventionsAppliedProperty, true);
 
-         };
 
- #if WINDOWS_PHONE
 
-         static void BindAppBar(DependencyObject view) {
 
-             var page = view as PhoneApplicationPage;
 
-             if (page == null || page.ApplicationBar == null) {
 
-                 return;
 
-             }
 
-             var triggers = Interaction.GetTriggers(view);
 
-             foreach(var item in page.ApplicationBar.Buttons) {
 
-                 var button = item as IAppBarActionMessage;
 
-                 if (button == null || string.IsNullOrEmpty(button.Message)) {
 
-                     continue;
 
-                 }
 
-                 var parsedTrigger = Parser.Parse(view, button.Message).First();
 
-                 var trigger = new AppBarItemTrigger(button);
 
-                 var actionMessages = parsedTrigger.Actions.OfType<ActionMessage>().ToList();
 
-                 actionMessages.Apply(x => {
 
-                     x.applicationBarSource = button;
 
-                     parsedTrigger.Actions.Remove(x);
 
-                     trigger.Actions.Add(x);
 
-                 });
 
-                 
 
-                 triggers.Add(trigger);
 
-             }
 
-             foreach (var item in page.ApplicationBar.MenuItems) {
 
-                 var menuItem = item as IAppBarActionMessage;
 
-                 if (menuItem == null || string.IsNullOrEmpty(menuItem.Message)) {
 
- 					continue;
 
-                 }
 
-                 var parsedTrigger = Parser.Parse(view, menuItem.Message).First();
 
-                 var trigger = new AppBarItemTrigger(menuItem);
 
-                 var actionMessages = parsedTrigger.Actions.OfType<ActionMessage>().ToList();
 
-                 actionMessages.Apply(x => {
 
-                     x.applicationBarSource = menuItem;
 
-                     parsedTrigger.Actions.Remove(x);
 
-                     trigger.Actions.Add(x);
 
-                 });
 
-                 triggers.Add(trigger);
 
-             }
 
-         }
 
- #endif
 
-     }
 
- }
 
 
  |