diff --git a/Source/Xamarin/Prism.Forms/AppModel/RuntimePlatform.cs b/Source/Xamarin/Prism.Forms/AppModel/RuntimePlatform.cs index f48741fb09..b490a93ddc 100644 --- a/Source/Xamarin/Prism.Forms/AppModel/RuntimePlatform.cs +++ b/Source/Xamarin/Prism.Forms/AppModel/RuntimePlatform.cs @@ -1,18 +1,18 @@ namespace Prism.AppModel { - /// - /// Represents the Platform (OS) that the application is running on. - /// - /// This enum acts as a wrapper around the Device.RuntimePlatform string-based options - public enum RuntimePlatform - { - Android, - iOS, - macOS, - Tizen, - UWP, - WinPhone, - WinRT, - Unknown - } + /// + /// Represents the Platform (OS) that the application is running on. + /// + /// This enum acts as a wrapper around the Device.RuntimePlatform string-based options + public enum RuntimePlatform + { + Android, + iOS, + macOS, + Tizen, + UWP, + WinPhone, + WinRT, + Unknown + } } diff --git a/Source/Xamarin/Prism.Forms/Ioc/AutoRegisterForNavigationAttribute.cs b/Source/Xamarin/Prism.Forms/Ioc/AutoRegisterForNavigationAttribute.cs new file mode 100644 index 0000000000..3317db0b5f --- /dev/null +++ b/Source/Xamarin/Prism.Forms/Ioc/AutoRegisterForNavigationAttribute.cs @@ -0,0 +1,10 @@ +using System; + +namespace Prism.Ioc +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] + public class AutoRegisterForNavigationAttribute : Attribute + { + public bool Automatic { get; set; } + } +} diff --git a/Source/Xamarin/Prism.Forms/Ioc/RegisterForNavigationAttribute.cs b/Source/Xamarin/Prism.Forms/Ioc/RegisterForNavigationAttribute.cs new file mode 100644 index 0000000000..76bcc2f61d --- /dev/null +++ b/Source/Xamarin/Prism.Forms/Ioc/RegisterForNavigationAttribute.cs @@ -0,0 +1,14 @@ +using Prism.AppModel; +using System; + +namespace Prism.Ioc +{ + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] + public class RegisterForNavigationAttribute : Attribute + { + public Type ViewType { get; set; } + public Type ViewModelType { get; set; } + public string Name { get; set; } + public RuntimePlatform? RuntimePlatform { get; set; } + } +} diff --git a/Source/Xamarin/Prism.Forms/Ioc/TypeAutoLoadExtensions.cs b/Source/Xamarin/Prism.Forms/Ioc/TypeAutoLoadExtensions.cs new file mode 100644 index 0000000000..9c35650f90 --- /dev/null +++ b/Source/Xamarin/Prism.Forms/Ioc/TypeAutoLoadExtensions.cs @@ -0,0 +1,88 @@ +using Prism.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Xamarin.Forms; + +namespace Prism.Ioc +{ + internal static class IContainerRegistryAutoLoadExtensions + { + public static void AutoRegisterViews(this Type type, IContainerRegistry containerRegistry) + { + if (!type.GetCustomAttributes().Any(a => a is AutoRegisterForNavigationAttribute)) return; + + var regAttr = type.GetCustomAttribute(); + var assembly = type.Assembly; + + if (regAttr.Automatic) + { + var viewTypes = assembly.ExportedTypes.Where(t => t.IsSubclassOf(typeof(Page))); + RegisterViewsAutomatically(containerRegistry, viewTypes); + } + else + { + RegisterViewsByAttribute(containerRegistry, assembly); + } + } + + private static void RegisterViewsAutomatically(IContainerRegistry containerRegistry, IEnumerable viewTypes) + { + foreach (var viewType in viewTypes) + { + containerRegistry.RegisterForNavigation(viewType, viewType.Name); + } + + if (!containerRegistry.IsRegistered(nameof(NavigationPage))) + { + containerRegistry.RegisterForNavigation(); + } + + if (!containerRegistry.IsRegistered(nameof(TabbedPage))) + { + containerRegistry.RegisterForNavigation(); + } + } + + private static void RegisterViewsByAttribute(IContainerRegistry containerRegistry, Assembly assembly) + { + var attrs = assembly.GetCustomAttributes(); + foreach (var attr in attrs) + { + RegisterViewByAttribute(containerRegistry, attr); + } + + var viewTypes = assembly.ExportedTypes.Where(t => t.IsSubclassOf(typeof(Page)) + && t.GetCustomAttributes().Any()); + foreach (var viewType in viewTypes) + { + var attr = viewType.GetCustomAttributes() + .FirstOrDefault(a => a.RuntimePlatform.ToString() == Device.RuntimePlatform || a.RuntimePlatform is null); + attr.ViewType = viewType; + RegisterViewByAttribute(containerRegistry, attr); + } + } + + private static void RegisterViewByAttribute(IContainerRegistry containerRegistry, RegisterForNavigationAttribute attr) + { + if (attr.ViewType is null) + throw new Exception($"Cannot auto register View. No ViewType was specified. Name: '{attr.Name}'. ViewModelType: '{attr.ViewModelType?.Name}'"); + + if (attr.RuntimePlatform != null && attr.RuntimePlatform.ToString() != Device.RuntimePlatform) return; + + var name = attr.Name; + if (string.IsNullOrEmpty(name)) + { + name = attr.ViewType.Name; + } + + containerRegistry.RegisterForNavigation(attr.ViewType, name); + + if (attr.ViewModelType != null) + { + ViewModelLocationProvider.Register(attr.ViewType.Name, attr.ViewModelType); + } + } + } +} diff --git a/Source/Xamarin/Prism.Forms/Modularity/ModuleInitializer.cs b/Source/Xamarin/Prism.Forms/Modularity/ModuleInitializer.cs index 5c9589c246..6b05e3cf0a 100644 --- a/Source/Xamarin/Prism.Forms/Modularity/ModuleInitializer.cs +++ b/Source/Xamarin/Prism.Forms/Modularity/ModuleInitializer.cs @@ -18,6 +18,7 @@ public void Initialize(IModuleInfo moduleInfo) if (module != null) { module.RegisterTypes(_container); + module.GetType().AutoRegisterViews(_container); module.OnInitialized(_container); } } diff --git a/Source/Xamarin/Prism.Forms/PrismApplicationBase.cs b/Source/Xamarin/Prism.Forms/PrismApplicationBase.cs index 454bc14da7..40877ea5b5 100644 --- a/Source/Xamarin/Prism.Forms/PrismApplicationBase.cs +++ b/Source/Xamarin/Prism.Forms/PrismApplicationBase.cs @@ -130,6 +130,7 @@ public virtual void Initialize() RegisterRequiredTypes(_containerExtension); PlatformInitializer?.RegisterTypes(_containerExtension); RegisterTypes(_containerExtension); + GetType().AutoRegisterViews(_containerExtension); _containerExtension.FinalizeExtension(); if(_setFormsDependencyResolver)