| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429 | 
							- #if XFORMS
 
- namespace Caliburn.Micro.Core.Xamarin.Forms
 
- #else
 
- namespace Caliburn.Micro
 
- #endif
 
- {
 
-     using System;
 
-     using System.Linq;
 
-     using System.Text.RegularExpressions;
 
-     using System.Windows;
 
-     using System.Collections.Generic;
 
-     using Caliburn.Micro.Core;
 
- #if WinRT
 
-     using Windows.UI.Xaml;
 
- #endif
 
- #if XFORMS
 
-     using UIElement = global::Xamarin.Forms.Element;
 
- #endif
 
-     /// <summary>
 
-     ///   A strategy for determining which view model to use for a given view.
 
-     /// </summary>
 
-     public static class ViewModelLocator
 
-     {
 
- #if ANDROID
 
-         const string DefaultViewSuffix = "Activity";
 
- #elif IOS
 
-         const string DefaultViewSuffix = "ViewController";
 
- #else
 
-         const string DefaultViewSuffix = "View";
 
- #endif
 
-         static readonly ILog Log = LogManager.GetLog(typeof(ViewModelLocator));
 
-         //These fields are used for configuring the default type mappings. They can be changed using ConfigureTypeMappings().
 
-         static string defaultSubNsViews;
 
-         static string defaultSubNsViewModels;
 
-         static bool useNameSuffixesInMappings;
 
-         static string nameFormat;
 
-         static string viewModelSuffix;
 
-         static readonly List<string> ViewSuffixList = new List<string>();
 
-         static bool includeViewSuffixInVmNames;
 
-         ///<summary>
 
-         /// Used to transform names.
 
-         ///</summary>
 
-         public static readonly NameTransformer NameTransformer = new NameTransformer();
 
-         /// <summary>
 
-         /// The name of the capture group used as a marker for rules that return interface types
 
-         /// </summary>
 
-         public static string InterfaceCaptureGroupName = "isinterface";
 
-         static ViewModelLocator() {
 
-             var configuration = new TypeMappingConfiguration();
 
- #if ANDROID
 
-             configuration.DefaultSubNamespaceForViews = "Activities";
 
-             configuration.ViewSuffixList.Add("Activity");
 
-             configuration.IncludeViewSuffixInViewModelNames = false;
 
- #elif IOS
 
-             configuration.DefaultSubNamespaceForViews = "ViewControllers";
 
-             configuration.ViewSuffixList.Add("ViewController");
 
-             configuration.IncludeViewSuffixInViewModelNames = false;
 
- #endif
 
-             ConfigureTypeMappings(configuration);
 
-         }
 
-         /// <summary>
 
-         /// Specifies how type mappings are created, including default type mappings. Calling this method will
 
-         /// clear all existing name transformation rules and create new default type mappings according to the
 
-         /// configuration.
 
-         /// </summary>
 
-         /// <param name="config">An instance of TypeMappingConfiguration that provides the settings for configuration</param>
 
-         public static void ConfigureTypeMappings(TypeMappingConfiguration config)
 
-         {
 
-             if (String.IsNullOrEmpty(config.DefaultSubNamespaceForViews))
 
-             {
 
-                 throw new ArgumentException("DefaultSubNamespaceForViews field cannot be blank.");
 
-             }
 
-             if (String.IsNullOrEmpty(config.DefaultSubNamespaceForViewModels))
 
-             {
 
-                 throw new ArgumentException("DefaultSubNamespaceForViewModels field cannot be blank.");
 
-             }
 
-             if (String.IsNullOrEmpty(config.NameFormat))
 
-             {
 
-                 throw new ArgumentException("NameFormat field cannot be blank.");
 
-             }
 
-             NameTransformer.Clear();
 
-             ViewSuffixList.Clear();
 
-             defaultSubNsViews = config.DefaultSubNamespaceForViews;
 
-             defaultSubNsViewModels = config.DefaultSubNamespaceForViewModels;
 
-             nameFormat = config.NameFormat;
 
-             useNameSuffixesInMappings = config.UseNameSuffixesInMappings;
 
-             viewModelSuffix = config.ViewModelSuffix;
 
-             ViewSuffixList.AddRange(config.ViewSuffixList);
 
-             includeViewSuffixInVmNames = config.IncludeViewSuffixInViewModelNames;
 
-             SetAllDefaults();
 
-         }
 
-         private static void SetAllDefaults()
 
-         {
 
-             if (useNameSuffixesInMappings)
 
-             {
 
-                 //Add support for all view suffixes
 
-                 ViewSuffixList.Apply(AddDefaultTypeMapping);
 
-             }
 
-             else
 
-             {
 
-                 AddSubNamespaceMapping(defaultSubNsViews, defaultSubNsViewModels);
 
-             }
 
-         }
 
-         /// <summary>
 
-         /// Adds a default type mapping using the standard namespace mapping convention
 
-         /// </summary>
 
-         /// <param name="viewSuffix">Suffix for type name. Should  be "View" or synonym of "View". (Optional)</param>
 
-         public static void AddDefaultTypeMapping(string viewSuffix = DefaultViewSuffix)
 
-         {
 
-             if (!useNameSuffixesInMappings)
 
-             {
 
-                 return;
 
-             }
 
-             //Check for <Namespace>.<BaseName><ViewSuffix> construct
 
-             AddNamespaceMapping(String.Empty, String.Empty, viewSuffix);
 
-             //Check for <Namespace>.Views.<NameSpace>.<BaseName><ViewSuffix> construct
 
-             AddSubNamespaceMapping(defaultSubNsViews, defaultSubNsViewModels, viewSuffix);
 
-         }
 
-         /// <summary>
 
-         /// Adds a standard type mapping based on namespace RegEx replace and filter patterns
 
-         /// </summary>
 
-         /// <param name="nsSourceReplaceRegEx">RegEx replace pattern for source namespace</param>
 
-         /// <param name="nsSourceFilterRegEx">RegEx filter pattern for source namespace</param>
 
-         /// <param name="nsTargetsRegEx">Array of RegEx replace values for target namespaces</param>
 
-         /// <param name="viewSuffix">Suffix for type name. Should  be "View" or synonym of "View". (Optional)</param>
 
-         public static void AddTypeMapping(string nsSourceReplaceRegEx, string nsSourceFilterRegEx, string[] nsTargetsRegEx, string viewSuffix = DefaultViewSuffix)
 
-         {
 
-             var replist = new List<string>();
 
-             Action<string> func;
 
-             const string basegrp = "${basename}";
 
-             var interfacegrp = "${" + InterfaceCaptureGroupName + "}";
 
-             if (useNameSuffixesInMappings)
 
-             {
 
-                 if (viewModelSuffix.Contains(viewSuffix) || !includeViewSuffixInVmNames)
 
-                 {
 
-                     var nameregex = String.Format(nameFormat, basegrp, viewModelSuffix);
 
-                     func = t =>
 
-                     {
 
-                         replist.Add(t + "I" + nameregex + interfacegrp);
 
-                         replist.Add(t + "I" + basegrp + interfacegrp);
 
-                         replist.Add(t + nameregex);
 
-                         replist.Add(t + basegrp);
 
-                     };
 
-                 }
 
-                 else
 
-                 {
 
-                     var nameregex = String.Format(nameFormat, basegrp, "${suffix}" + viewModelSuffix);
 
-                     func = t =>
 
-                     {
 
-                         replist.Add(t + "I" + nameregex + interfacegrp);
 
-                         replist.Add(t + nameregex);
 
-                     };
 
-                 }
 
-             }
 
-             else
 
-             {
 
-                 func = t =>
 
-                 {
 
-                     replist.Add(t + "I" + basegrp + interfacegrp);
 
-                     replist.Add(t + basegrp);
 
-                 };
 
-             }
 
-             nsTargetsRegEx.ToList().Apply(t => func(t));
 
-             string suffix = useNameSuffixesInMappings ? viewSuffix : String.Empty;
 
-             var srcfilterregx = String.IsNullOrEmpty(nsSourceFilterRegEx)
 
-                 ? null
 
-                 : String.Concat(nsSourceFilterRegEx, String.Format(nameFormat, RegExHelper.NameRegEx, suffix), "$");
 
-             var rxbase = RegExHelper.GetNameCaptureGroup("basename");
 
-             var rxsuffix = RegExHelper.GetCaptureGroup("suffix", suffix);
 
-             //Add a dummy capture group -- place after the "$" so it can never capture anything
 
-             var rxinterface = RegExHelper.GetCaptureGroup(InterfaceCaptureGroupName, String.Empty);
 
-             NameTransformer.AddRule(
 
-                 String.Concat(nsSourceReplaceRegEx, String.Format(nameFormat, rxbase, rxsuffix), "$", rxinterface),
 
-                 replist.ToArray(),
 
-                 srcfilterregx
 
-             );
 
-         }
 
-         /// <summary>
 
-         /// Adds a standard type mapping based on namespace RegEx replace and filter patterns
 
-         /// </summary>
 
-         /// <param name="nsSourceReplaceRegEx">RegEx replace pattern for source namespace</param>
 
-         /// <param name="nsSourceFilterRegEx">RegEx filter pattern for source namespace</param>
 
-         /// <param name="nsTargetRegEx">RegEx replace value for target namespace</param>
 
-         /// <param name="viewSuffix">Suffix for type name. Should  be "View" or synonym of "View". (Optional)</param>
 
-         public static void AddTypeMapping(string nsSourceReplaceRegEx, string nsSourceFilterRegEx, string nsTargetRegEx, string viewSuffix = DefaultViewSuffix)
 
-         {
 
-             AddTypeMapping(nsSourceReplaceRegEx, nsSourceFilterRegEx, new[] { nsTargetRegEx }, viewSuffix);
 
-         }
 
-         /// <summary>
 
-         /// Adds a standard type mapping based on simple namespace mapping
 
-         /// </summary>
 
-         /// <param name="nsSource">Namespace of source type</param>
 
-         /// <param name="nsTargets">Namespaces of target type as an array</param>
 
-         /// <param name="viewSuffix">Suffix for type name. Should  be "View" or synonym of "View". (Optional)</param>
 
-         public static void AddNamespaceMapping(string nsSource, string[] nsTargets, string viewSuffix = DefaultViewSuffix)
 
-         {
 
-             //need to terminate with "." in order to concatenate with type name later
 
-             var nsencoded = RegExHelper.NamespaceToRegEx(nsSource + ".");
 
-             //Start pattern search from beginning of string ("^")
 
-             //unless original string was blank (i.e. special case to indicate "append target to source")
 
-             if (!String.IsNullOrEmpty(nsSource))
 
-             {
 
-                 nsencoded = "^" + nsencoded;
 
-             }
 
-             //Capture namespace as "origns" in case we need to use it in the output in the future
 
-             var nsreplace = RegExHelper.GetCaptureGroup("origns", nsencoded);
 
-             var nsTargetsRegEx = nsTargets.Select(t => t + ".").ToArray();
 
-             AddTypeMapping(nsreplace, null, nsTargetsRegEx, viewSuffix);
 
-         }
 
-         /// <summary>
 
-         /// Adds a standard type mapping based on simple namespace mapping
 
-         /// </summary>
 
-         /// <param name="nsSource">Namespace of source type</param>
 
-         /// <param name="nsTarget">Namespace of target type</param>
 
-         /// <param name="viewSuffix">Suffix for type name. Should  be "View" or synonym of "View". (Optional)</param>
 
-         public static void AddNamespaceMapping(string nsSource, string nsTarget, string viewSuffix = DefaultViewSuffix)
 
-         {
 
-             AddNamespaceMapping(nsSource, new[] { nsTarget }, viewSuffix);
 
-         }
 
-         /// <summary>
 
-         /// Adds a standard type mapping by substituting one subnamespace for another
 
-         /// </summary>
 
-         /// <param name="nsSource">Subnamespace of source type</param>
 
-         /// <param name="nsTargets">Subnamespaces of target type as an array</param>
 
-         /// <param name="viewSuffix">Suffix for type name. Should  be "View" or synonym of "View". (Optional)</param>
 
-         public static void AddSubNamespaceMapping(string nsSource, string[] nsTargets, string viewSuffix = DefaultViewSuffix)
 
-         {
 
-             //need to terminate with "." in order to concatenate with type name later
 
-             var nsencoded = RegExHelper.NamespaceToRegEx(nsSource + ".");
 
-             string rxbeforetgt, rxaftersrc, rxaftertgt;
 
-             string rxbeforesrc = rxbeforetgt = rxaftersrc = rxaftertgt = String.Empty;
 
-             if (!String.IsNullOrEmpty(nsSource))
 
-             {
 
-                 if (!nsSource.StartsWith("*"))
 
-                 {
 
-                     rxbeforesrc = RegExHelper.GetNamespaceCaptureGroup("nsbefore");
 
-                     rxbeforetgt = @"${nsbefore}";
 
-                 }
 
-                 if (!nsSource.EndsWith("*"))
 
-                 {
 
-                     rxaftersrc = RegExHelper.GetNamespaceCaptureGroup("nsafter");
 
-                     rxaftertgt = "${nsafter}";
 
-                 }
 
-             }
 
-             var rxmid = RegExHelper.GetCaptureGroup("subns", nsencoded);
 
-             var nsreplace = String.Concat(rxbeforesrc, rxmid, rxaftersrc);
 
-             var nsTargetsRegEx = nsTargets.Select(t => String.Concat(rxbeforetgt, t, ".", rxaftertgt)).ToArray();
 
-             AddTypeMapping(nsreplace, null, nsTargetsRegEx, viewSuffix);
 
-         }
 
-         /// <summary>
 
-         /// Adds a standard type mapping by substituting one subnamespace for another
 
-         /// </summary>
 
-         /// <param name="nsSource">Subnamespace of source type</param>
 
-         /// <param name="nsTarget">Subnamespace of target type</param>
 
-         /// <param name="viewSuffix">Suffix for type name. Should  be "View" or synonym of "View". (Optional)</param>
 
-         public static void AddSubNamespaceMapping(string nsSource, string nsTarget, string viewSuffix = DefaultViewSuffix)
 
-         {
 
-             AddSubNamespaceMapping(nsSource, new[] { nsTarget }, viewSuffix);
 
-         }
 
-         /// <summary>
 
-         ///   Makes a type name into an interface name.
 
-         /// </summary>
 
-         /// <param name = "typeName">The part.</param>
 
-         /// <returns></returns>
 
-         public static string MakeInterface(string typeName)
 
-         {
 
-             var suffix = string.Empty;
 
-             if (typeName.Contains("[["))
 
-             {
 
-                 //generic type
 
-                 var genericParStart = typeName.IndexOf("[[");
 
-                 suffix = typeName.Substring(genericParStart);
 
-                 typeName = typeName.Remove(genericParStart);
 
-             }
 
-             var index = typeName.LastIndexOf(".");
 
-             return typeName.Insert(index + 1, "I") + suffix;
 
-         }
 
-         /// <summary>
 
-         /// Transforms a View type name into all of its possible ViewModel type names. Accepts a flag
 
-         /// to include or exclude interface types.
 
-         /// </summary>
 
-         /// <returns>Enumeration of transformed names</returns>
 
-         /// <remarks>Arguments:
 
-         /// typeName = The name of the View type being resolved to its companion ViewModel.
 
-         /// includeInterfaces = Flag to indicate if interface types are included
 
-         /// </remarks>
 
-         public static Func<string, bool, IEnumerable<string>> TransformName = (typeName, includeInterfaces) =>
 
-         {
 
-             Func<string, string> getReplaceString;
 
-             if (includeInterfaces)
 
-             {
 
-                 getReplaceString = r => r;
 
-             }
 
-             else
 
-             {
 
-                 var interfacegrpregex = @"\${" + InterfaceCaptureGroupName + @"}$";
 
-                 getReplaceString = r => Regex.IsMatch(r, interfacegrpregex) ? String.Empty : r;
 
-             }
 
-             return NameTransformer.Transform(typeName, getReplaceString).Where(n => n != String.Empty);
 
-         };
 
-         /// <summary>
 
-         ///   Determines the view model type based on the specified view type.
 
-         /// </summary>
 
-         /// <returns>The view model type.</returns>
 
-         /// <remarks>
 
-         ///   Pass the view type and receive a view model type. Pass true for the second parameter to search for interfaces.
 
-         /// </remarks>
 
-         public static Func<Type, bool, Type> LocateTypeForViewType = (viewType, searchForInterface) =>
 
-         {
 
-             var typeName = viewType.FullName;
 
-             var viewModelTypeList = TransformName(typeName, searchForInterface).ToList();
 
-             var viewModelType = AssemblySource.FindTypeByNames(viewModelTypeList);
 
-             if (viewModelType == null)
 
-             {
 
-                 Log.Warn("View Model not found. Searched: {0}.", string.Join(", ", viewModelTypeList.ToArray()));
 
-             }
 
-             return viewModelType;
 
-         };
 
-         /// <summary>
 
-         ///   Locates the view model for the specified view type.
 
-         /// </summary>
 
-         /// <returns>The view model.</returns>
 
-         /// <remarks>
 
-         ///   Pass the view type as a parameter and receive a view model instance.
 
-         /// </remarks>
 
-         public static Func<Type, object> LocateForViewType = viewType =>
 
-         {
 
-             var viewModelType = LocateTypeForViewType(viewType, false);
 
-             if (viewModelType != null)
 
-             {
 
-                 var viewModel = IoC.GetInstance(viewModelType, null);
 
-                 if (viewModel != null)
 
-                 {
 
-                     return viewModel;
 
-                 }
 
-             }
 
-             viewModelType = LocateTypeForViewType(viewType, true);
 
-             return viewModelType != null
 
-                        ? IoC.GetInstance(viewModelType, null)
 
-                        : null;
 
-         };
 
-         /// <summary>
 
-         ///   Locates the view model for the specified view instance.
 
-         /// </summary>
 
-         /// <returns>The view model.</returns>
 
-         /// <remarks>
 
-         ///   Pass the view instance as a parameters and receive a view model instance.
 
-         /// </remarks>
 
-         public static Func<object, object> LocateForView = view =>
 
-         {
 
-             if (view == null)
 
-             {
 
-                 return null;
 
-             }
 
- #if ANDROID || IOS
 
-              return LocateForViewType(view.GetType());
 
- #elif XFORMS
 
-             var frameworkElement = view as UIElement;
 
-             if (frameworkElement != null && frameworkElement.BindingContext != null)
 
-             {
 
-                 return frameworkElement.BindingContext;
 
-             }
 
-             return LocateForViewType(view.GetType());
 
- #else
 
-             var frameworkElement = view as FrameworkElement;
 
-             if (frameworkElement != null && frameworkElement.DataContext != null)
 
-             {
 
-                 return frameworkElement.DataContext;
 
-             }
 
-             return LocateForViewType(view.GetType());
 
- #endif
 
-         };
 
-     }
 
- }
 
 
  |