diff --git a/Directory.Build.props b/Directory.Build.props
index f7d8373..1bfc993 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -5,6 +5,7 @@
Dan Siegel
https://github.com/dansiegel/Prism.Maui
LICENSE
+ ReadMe.md
prism-logo.png
false
$(MSBuildThisFileDirectory)Artifacts
@@ -27,6 +28,10 @@
+
();
- //regionManager.RegisterViewWithRegion("ContentRegion", "RegionViewA");
+ var regionManager = containerProvider.Resolve();
+ regionManager.RegisterViewWithRegion("ContentRegion", "RegionViewA");
}
public void RegisterTypes(IContainerRegistry containerRegistry)
diff --git a/sample/MauiRegionsModule/ViewModels/ContentRegionPageViewModel.cs b/sample/MauiRegionsModule/ViewModels/ContentRegionPageViewModel.cs
index 114b8ae..9bf3225 100644
--- a/sample/MauiRegionsModule/ViewModels/ContentRegionPageViewModel.cs
+++ b/sample/MauiRegionsModule/ViewModels/ContentRegionPageViewModel.cs
@@ -13,7 +13,7 @@ public ContentRegionPageViewModel(IRegionManager regionManager)
public void Initialize(INavigationParameters parameters)
{
- _regionManager.RequestNavigate("ContentRegion", "RegionViewA");
+ //_regionManager.RequestNavigate("ContentRegion", "RegionViewA");
}
public DelegateCommand NavigateCommand { get; }
diff --git a/sample/MauiRegionsModule/ViewModels/RegionViewModelBase.cs b/sample/MauiRegionsModule/ViewModels/RegionViewModelBase.cs
index 2f36cd8..b602875 100644
--- a/sample/MauiRegionsModule/ViewModels/RegionViewModelBase.cs
+++ b/sample/MauiRegionsModule/ViewModels/RegionViewModelBase.cs
@@ -2,7 +2,7 @@
namespace MauiRegionsModule.ViewModels;
-public abstract class RegionViewModelBase : BindableBase, IRegionAware
+public abstract class RegionViewModelBase : BindableBase, IRegionAware, IPageLifecycleAware
{
protected string Name => GetType().Name.Replace("ViewModel", string.Empty);
protected INavigationService _navigationService { get; }
@@ -47,4 +47,13 @@ public void OnNavigatedTo(INavigationContext navigationContext)
_regionNavigation = navigationContext.NavigationService;
ViewCount = navigationContext.NavigationService.Region.Views.Count();
}
+
+ public void OnAppearing()
+ {
+ RaisePropertyChanged(nameof(PageName));
+ }
+
+ public void OnDisappearing()
+ {
+ }
}
diff --git a/sample/PrismMauiDemo/MauiProgram.cs b/sample/PrismMauiDemo/MauiProgram.cs
index a26359c..d4c8bd3 100644
--- a/sample/PrismMauiDemo/MauiProgram.cs
+++ b/sample/PrismMauiDemo/MauiProgram.cs
@@ -34,6 +34,9 @@ public static MauiApp CreateMauiApp()
var status = x.Cancelled ? "Cancelled" : x.Result.Success ? "Success" : "Failed";
Console.WriteLine($"Result: {status}");
+
+ if (status == "Failed" && !string.IsNullOrEmpty(x.Result?.Exception?.Message))
+ Console.Error.WriteLine(x.Result.Exception.Message);
}))
.OnAppStart(navigationService => navigationService.CreateBuilder()
.AddNavigationSegment()
diff --git a/src/Prism.DryIoc.Shared/DryIocContainerExtension.cs b/src/Prism.DryIoc.Shared/DryIocContainerExtension.cs
index b78d83c..f6a851c 100644
--- a/src/Prism.DryIoc.Shared/DryIocContainerExtension.cs
+++ b/src/Prism.DryIoc.Shared/DryIocContainerExtension.cs
@@ -295,7 +295,11 @@ public object Resolve(Type type, params (Type Type, object Instance)[] parameter
try
{
var container = _currentScope?.Resolver ?? Instance;
- return container.Resolve(type, args: parameters.Select(p => p.Instance).ToArray());
+ var args = parameters.Where(x => x.Instance is not IContainerProvider)
+ .Select(x => x.Instance)
+ .ToList();
+ args.Add(this);
+ return container.Resolve(type, args: args.ToArray());
}
catch (Exception ex)
{
@@ -315,7 +319,11 @@ public object Resolve(Type type, string name, params (Type Type, object Instance
try
{
var container = _currentScope?.Resolver ?? Instance;
- return container.Resolve(type, name, args: parameters.Select(p => p.Instance).ToArray());
+ var args = parameters.Where(x => x.Instance is not IContainerProvider)
+ .Select(x => x.Instance)
+ .ToList();
+ args.Add(this);
+ return container.Resolve(type, name, args: args.ToArray());
}
catch (Exception ex)
{
@@ -391,7 +399,7 @@ public DryIocScopedProvider(IResolverContext resolver)
public IResolverContext Resolver { get; private set; }
public IScopedProvider CurrentScope => this;
- public IScopedProvider CreateScope() => this;
+ public IScopedProvider CreateScope() => new DryIocScopedProvider(Resolver.OpenScope());
public void Dispose()
{
@@ -409,7 +417,11 @@ public object Resolve(Type type, params (Type Type, object Instance)[] parameter
{
try
{
- return Resolver.Resolve(type, args: parameters.Select(p => p.Instance).ToArray());
+ var args = parameters.Where(x => x.Instance is not IContainerProvider)
+ .Select(x => x.Instance)
+ .ToList();
+ args.Add(this);
+ return Resolver.Resolve(type, args: args.ToArray());
}
catch (Exception ex)
{
@@ -421,7 +433,11 @@ public object Resolve(Type type, string name, params (Type Type, object Instance
{
try
{
- return Resolver.Resolve(type, name, args: parameters.Select(p => p.Instance).ToArray());
+ var args = parameters.Where(x => x.Instance is not IContainerProvider)
+ .Select(x => x.Instance)
+ .ToList();
+ args.Add(this);
+ return Resolver.Resolve(type, name, args: args.ToArray());
}
catch (Exception ex)
{
diff --git a/src/Prism.Maui/Behaviors/DelayedRegionCreationCallbackBehavior.cs b/src/Prism.Maui/Behaviors/DelayedRegionCreationCallbackBehavior.cs
index b8797ac..8a90e53 100644
--- a/src/Prism.Maui/Behaviors/DelayedRegionCreationCallbackBehavior.cs
+++ b/src/Prism.Maui/Behaviors/DelayedRegionCreationCallbackBehavior.cs
@@ -1,5 +1,6 @@
using System.ComponentModel;
using Prism.Extensions;
+using Prism.Navigation.Xaml;
namespace Prism.Behaviors;
@@ -40,10 +41,10 @@ private void OnParentChanged(object sender, EventArgs e)
private void PagePropertyChanged(object sender, PropertyChangedEventArgs e)
{
- if (sender is not Page page)
+ if (sender is not Page page || e.PropertyName != Navigation.Xaml.Navigation.PrismContainerProvider)
return;
- var container = page.GetValue(Navigation.Xaml.Navigation.NavigationScopeProperty);
+ var container = page.GetContainerProvider();
if(container is not null)
{
diff --git a/src/Prism.Maui/Behaviors/PageScopeBehavior.cs b/src/Prism.Maui/Behaviors/PageScopeBehavior.cs
index 5c851dc..4fe1313 100644
--- a/src/Prism.Maui/Behaviors/PageScopeBehavior.cs
+++ b/src/Prism.Maui/Behaviors/PageScopeBehavior.cs
@@ -1,4 +1,6 @@
-namespace Prism.Behaviors;
+using Prism.Navigation.Xaml;
+
+namespace Prism.Behaviors;
///
/// Controls the Page container Scope
@@ -16,6 +18,6 @@ protected override void OnDetachingFrom(Page page)
{
base.OnDetachingFrom(page);
// This forces the Attached Property to get cleaned up.
- page.SetValue(Navigation.Xaml.Navigation.NavigationScopeProperty, null);
+ page.SetContainerProvider(null);
}
}
diff --git a/src/Prism.Maui/Behaviors/RegionCleanupBehavior.cs b/src/Prism.Maui/Behaviors/RegionCleanupBehavior.cs
index 6eda320..0e83df7 100644
--- a/src/Prism.Maui/Behaviors/RegionCleanupBehavior.cs
+++ b/src/Prism.Maui/Behaviors/RegionCleanupBehavior.cs
@@ -1,4 +1,5 @@
using Prism.Ioc;
+using Prism.Navigation.Xaml;
using Prism.Regions;
namespace Prism.Behaviors;
@@ -8,9 +9,9 @@ internal class RegionCleanupBehavior : BehaviorBase
private WeakReference _regionReference;
public RegionCleanupBehavior(IRegion region)
-{
+ {
_regionReference = new WeakReference(region);
-}
+ }
public IRegion Region => _regionReference.TryGetTarget(out var target) ? target : null;
@@ -18,7 +19,7 @@ protected override void OnDetachingFrom(Page bindable)
{
if (Region != null)
{
- var container = bindable.GetValue(Navigation.Xaml.Navigation.NavigationScopeProperty) as IContainerProvider;
+ var container = bindable.GetContainerProvider();
var manager = Region.RegionManager ?? container.Resolve();
if (manager.Regions.ContainsRegionWithName(Region.Name))
{
diff --git a/src/Prism.Maui/Common/IRegistryAware.cs b/src/Prism.Maui/Common/IRegistryAware.cs
new file mode 100644
index 0000000..4639126
--- /dev/null
+++ b/src/Prism.Maui/Common/IRegistryAware.cs
@@ -0,0 +1,8 @@
+using Prism.Mvvm;
+
+namespace Prism.Common;
+
+public interface IRegistryAware
+{
+ IViewRegistry Registry { get; }
+}
\ No newline at end of file
diff --git a/src/Prism.Maui/Common/MvvmHelpers.cs b/src/Prism.Maui/Common/MvvmHelpers.cs
index 0726040..a7e73d2 100644
--- a/src/Prism.Maui/Common/MvvmHelpers.cs
+++ b/src/Prism.Maui/Common/MvvmHelpers.cs
@@ -1,6 +1,7 @@
using System.ComponentModel;
using System.Reflection;
using Prism.Navigation;
+using Prism.Navigation.Xaml;
using Prism.Regions.Navigation;
using NavigationMode = Prism.Navigation.NavigationMode;
@@ -19,6 +20,13 @@ public static void InvokeViewAndViewModelAction(object view, Action action
{
action(viewModelAsT);
}
+
+ if(view is Page page)
+ {
+ var children = page.GetChildViews();
+ foreach (var child in children)
+ InvokeViewAndViewModelAction(child, action);
+ }
}
public static async Task InvokeViewAndViewModelActionAsync(object view, Func action) where T : class
@@ -32,6 +40,13 @@ public static async Task InvokeViewAndViewModelActionAsync(object view, Func<
{
await action(viewModelAsT);
}
+
+ if (view is Page page)
+ {
+ var children = page.GetChildViews();
+ foreach (var child in children)
+ await InvokeViewAndViewModelActionAsync(child, action);
+ }
}
public static void DestroyPage(IView view)
@@ -104,15 +119,9 @@ public static T GetImplementerFromViewOrViewModel(object view)
public static bool IsNavigationTarget(object view, INavigationContext navigationContext)
{
- if (view is IRegionAware viewAsRegionAware)
- {
- return viewAsRegionAware.IsNavigationTarget(navigationContext);
- }
-
- if (view is BindableObject bindable && bindable.BindingContext is IRegionAware vmAsRegionAware)
- {
- return vmAsRegionAware.IsNavigationTarget(navigationContext);
- }
+ var implementor = GetImplementerFromViewOrViewModel(view);
+ if (implementor is not null)
+ return implementor.IsNavigationTarget(navigationContext);
var uri = navigationContext.Uri;
if (!uri.IsAbsoluteUri)
diff --git a/src/Prism.Maui/Navigation/ViewRegistration.cs b/src/Prism.Maui/Common/ViewRegistration.cs
similarity index 69%
rename from src/Prism.Maui/Navigation/ViewRegistration.cs
rename to src/Prism.Maui/Common/ViewRegistration.cs
index 5e277de..f59de8a 100644
--- a/src/Prism.Maui/Navigation/ViewRegistration.cs
+++ b/src/Prism.Maui/Common/ViewRegistration.cs
@@ -1,7 +1,8 @@
-namespace Prism.Navigation;
+namespace Prism.Common;
public record ViewRegistration
{
+ public ViewType Type { get; init; }
public Type View { get; init; }
public Type ViewModel { get; init; }
public string Name { get; init; }
diff --git a/src/Prism.Maui/Common/ViewType.cs b/src/Prism.Maui/Common/ViewType.cs
new file mode 100644
index 0000000..a8a68a5
--- /dev/null
+++ b/src/Prism.Maui/Common/ViewType.cs
@@ -0,0 +1,9 @@
+namespace Prism.Common;
+
+public enum ViewType
+{
+ Unknown,
+ Page,
+ Region,
+ Dialog,
+}
diff --git a/src/Prism.Maui/Ioc/IResolverOverridesHelper.cs b/src/Prism.Maui/Ioc/IResolverOverridesHelper.cs
deleted file mode 100644
index 0741441..0000000
--- a/src/Prism.Maui/Ioc/IResolverOverridesHelper.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace Prism.Ioc;
-
-///
-/// Provides a helper interface for Regions to be able to inject the current Region
-///
-public interface IResolverOverridesHelper
-{
- IEnumerable<(Type Type, object Instance)> GetOverrides();
-}
\ No newline at end of file
diff --git a/src/Prism.Maui/Ioc/MicrosoftDependencyInjectionExtensions.cs b/src/Prism.Maui/Ioc/MicrosoftDependencyInjectionExtensions.cs
index a098dbe..e0800f4 100644
--- a/src/Prism.Maui/Ioc/MicrosoftDependencyInjectionExtensions.cs
+++ b/src/Prism.Maui/Ioc/MicrosoftDependencyInjectionExtensions.cs
@@ -1,4 +1,4 @@
-using Prism.Navigation;
+using Prism.Common;
namespace Prism.Ioc;
@@ -36,8 +36,14 @@ public static IServiceCollection RegisterForNavigation(this IServiceCollection s
if (string.IsNullOrEmpty(name))
name = view.Name;
- NavigationRegistry.Register(view, viewModel, name);
- services.AddTransient(view);
+ services.AddSingleton(new ViewRegistration
+ {
+ Type = ViewType.Page,
+ Name = name,
+ View = view,
+ ViewModel = viewModel
+ })
+ .AddTransient(view);
if (viewModel != null)
services.AddTransient(viewModel);
diff --git a/src/Prism.Maui/Ioc/NavigationRegistrationExtensions.cs b/src/Prism.Maui/Ioc/NavigationRegistrationExtensions.cs
index d4f691f..00a786c 100644
--- a/src/Prism.Maui/Ioc/NavigationRegistrationExtensions.cs
+++ b/src/Prism.Maui/Ioc/NavigationRegistrationExtensions.cs
@@ -1,4 +1,4 @@
-using Prism.Navigation;
+using Prism.Common;
namespace Prism.Ioc;
@@ -20,8 +20,14 @@ public static IContainerRegistry RegisterForNavigation(this IContainerRegistry c
if (string.IsNullOrEmpty(name))
name = view.Name;
- NavigationRegistry.Register(view, viewModel, name);
- container.Register(view);
+ container.RegisterInstance(new ViewRegistration
+ {
+ Type = ViewType.Page,
+ Name = name,
+ View = view,
+ ViewModel = viewModel
+ })
+ .Register(view);
if (viewModel != null)
container.Register(viewModel);
diff --git a/src/Prism.Maui/Ioc/RegionNavigationRegistrationExtensions.cs b/src/Prism.Maui/Ioc/RegionNavigationRegistrationExtensions.cs
index b7543d3..d2ef037 100644
--- a/src/Prism.Maui/Ioc/RegionNavigationRegistrationExtensions.cs
+++ b/src/Prism.Maui/Ioc/RegionNavigationRegistrationExtensions.cs
@@ -1,4 +1,5 @@
using Microsoft.Maui.Controls.Compatibility;
+using Prism.Common;
using Prism.Regions;
using Prism.Regions.Adapters;
using Prism.Regions.Behaviors;
@@ -38,9 +39,14 @@ private static IContainerRegistry RegisterForNavigationWithViewModel(this IConta
if (viewModelType is not null)
containerRegistry.Register(viewModelType);
- containerRegistry.Register(viewType);
-
- RegionNavigationRegistry.Register(viewType, viewModelType, name);
+ containerRegistry.Register(viewType)
+ .RegisterInstance(new ViewRegistration
+ {
+ Name = name,
+ Type = ViewType.Region,
+ View = viewType,
+ ViewModel = viewModelType
+ });
return containerRegistry;
}
@@ -75,15 +81,21 @@ private static IServiceCollection RegisterForNavigationWithViewModel(this IServi
if (viewModelType is not null)
services.AddTransient(viewModelType);
- services.AddTransient(viewType);
-
- RegionNavigationRegistry.Register(viewType, viewModelType, name);
+ services.AddTransient(viewType)
+ .AddSingleton(new ViewRegistration
+ {
+ Name = name,
+ Type = ViewType.Region,
+ View = viewType,
+ ViewModel = viewModelType
+ });
return services;
}
internal static IContainerRegistry RegisterRegionServices(this IContainerRegistry containerRegistry, Action configureAdapters = null, Action configureBehaviors = null)
{
+ containerRegistry.Register();
containerRegistry.RegisterSingleton(p =>
{
var regionAdapterMappings = new RegionAdapterMappings();
diff --git a/src/Prism.Maui/Mvvm/IViewRegistry.cs b/src/Prism.Maui/Mvvm/IViewRegistry.cs
new file mode 100644
index 0000000..f81ac5f
--- /dev/null
+++ b/src/Prism.Maui/Mvvm/IViewRegistry.cs
@@ -0,0 +1,19 @@
+using Prism.Common;
+using Prism.Ioc;
+
+namespace Prism.Mvvm;
+
+public interface IViewRegistry
+{
+ IEnumerable Registrations { get; }
+
+ object CreateView(IContainerProvider container, string name);
+
+ Type GetViewType(string name);
+
+ string GetViewModelNavigationKey(Type viewModelType);
+
+ IEnumerable ViewsOfType(Type baseType);
+
+ bool IsRegistered(string name);
+}
diff --git a/src/Prism.Maui/Mvvm/ViewModelLocator.cs b/src/Prism.Maui/Mvvm/ViewModelLocator.cs
index cfd2d83..f4da63c 100644
--- a/src/Prism.Maui/Mvvm/ViewModelLocator.cs
+++ b/src/Prism.Maui/Mvvm/ViewModelLocator.cs
@@ -18,6 +18,9 @@ public static class ViewModelLocator
null,
propertyChanged: OnViewModelPropertyChanged);
+ internal static readonly BindableProperty NavigationNameProperty =
+ BindableProperty.CreateAttached("NavigationName", typeof(string), typeof(ViewModelLocator), null);
+
///
/// Gets the AutowireViewModel property value.
///
diff --git a/src/Prism.Maui/Mvvm/ViewRegistryBase.cs b/src/Prism.Maui/Mvvm/ViewRegistryBase.cs
new file mode 100644
index 0000000..2c2d732
--- /dev/null
+++ b/src/Prism.Maui/Mvvm/ViewRegistryBase.cs
@@ -0,0 +1,149 @@
+using System.Text.RegularExpressions;
+using Prism.Common;
+using Prism.Ioc;
+using Prism.Navigation.Xaml;
+
+namespace Prism.Mvvm;
+
+public abstract class ViewRegistryBase : IViewRegistry
+{
+ private readonly IEnumerable _registrations;
+ private readonly ViewType _registryType;
+
+ protected ViewRegistryBase(ViewType registryType, IEnumerable registrations)
+ {
+ _registrations = registrations;
+ _registryType = registryType;
+ }
+
+ public IEnumerable Registrations =>
+ _registrations.Where(x => x.Type == _registryType);
+
+ public Type GetViewType(string name) =>
+ GetRegistration(name)?.View;
+
+ public object CreateView(IContainerProvider container, string name)
+ {
+ try
+ {
+ var registration = GetRegistration(name);
+ if (registration is null)
+ throw new KeyNotFoundException($"No view with the name '{name}' has been registered");
+
+ var view = container.Resolve(registration.View) as BindableObject;
+ view.SetValue(ViewModelLocator.NavigationNameProperty, registration.Name);
+
+ view.SetContainerProvider(container);
+ ConfigureView(view, container);
+
+ if (registration.ViewModel is not null)
+ view.SetValue(ViewModelLocator.ViewModelProperty, registration.ViewModel);
+
+ Autowire(view);
+
+ return view;
+ }
+ catch (KeyNotFoundException)
+ {
+ throw;
+ }
+ catch (Exception ex)
+ {
+ throw new Exception($"Unable to create {_registryType} '{name}'.", ex);
+ }
+ }
+
+ private IEnumerable GetCandidates(Type viewModelType)
+ {
+ var names = new List
+ {
+ Regex.Replace(viewModelType.Name, @"ViewModel$", string.Empty),
+ Regex.Replace(viewModelType.Name, @"Model$", string.Empty),
+ };
+
+ if (_registryType == ViewType.Page)
+ names.Add(Regex.Replace(viewModelType.Name, @"ViewModel$", "Page"));
+ else if (_registryType == ViewType.Region)
+ names.Add(Regex.Replace(viewModelType.Name, @"ViewModel$", "Region"));
+ else if (_registryType == ViewType.Dialog)
+ names.Add(Regex.Replace(viewModelType.Name, @"ViewModel$", "Dialog"));
+
+ names = names.Where(x => !x.EndsWith("PagePage")).ToList();
+
+ var namespaces = _registryType switch
+ {
+ ViewType.Page => new[]
+ {
+ viewModelType.Namespace.Replace("ViewModels", "Views"),
+ viewModelType.Namespace.Replace("ViewModels", "Pages")
+ },
+ ViewType.Region => new[]
+ {
+ viewModelType.Namespace.Replace("ViewModels", "Views"),
+ viewModelType.Namespace.Replace("ViewModels", "Regions")
+ },
+ ViewType.Dialog => new[]
+ {
+ viewModelType.Namespace.Replace("ViewModels", "Views"),
+ viewModelType.Namespace.Replace("ViewModels", "Dialogs")
+ },
+ _ => new[]
+ {
+ viewModelType.Namespace.Replace("ViewModels", "Views"),
+ }
+ };
+
+ var candidates = namespaces.Select(@namespace => names.Select(name => $"{@namespace}.{name}"))
+ .SelectMany(x => x)
+ .Select(x => viewModelType.AssemblyQualifiedName.Replace(viewModelType.FullName, x));
+ return candidates
+ .Select(x => Type.GetType(x, false))
+ .Where(x => x is not null);
+ }
+
+ public string GetViewModelNavigationKey(Type viewModelType)
+ {
+ var registration = Registrations.LastOrDefault(x => x.ViewModel == viewModelType);
+ if (registration is not null)
+ return registration.Name;
+
+ var candidates = GetCandidates(viewModelType);
+ registration = Registrations.LastOrDefault(x => candidates.Any(c => c == x.View));
+ if (registration is not null)
+ {
+ return registration.Name;
+ }
+
+ throw new KeyNotFoundException($"No View with the ViewModel '{viewModelType.Name}' has been registered");
+ }
+
+ public IEnumerable ViewsOfType(Type baseType) =>
+ Registrations.Where(x => x.View == baseType || x.View.IsAssignableTo(baseType));
+
+ public bool IsRegistered(string name) =>
+ GetRegistration(name) is not null;
+
+ protected ViewRegistration GetRegistration(string name) =>
+ Registrations.LastOrDefault(x => x.Name == name);
+
+ protected abstract void ConfigureView(BindableObject bindable, IContainerProvider container);
+
+ protected void Autowire(BindableObject view)
+ {
+ if (view.BindingContext is not null)
+ return;
+
+ ViewModelLocator.Autowire(view);
+ }
+
+ //public static Type GetPageType(string name)
+ //{
+ // var registrations = _registrations.Where(x => x.Name == name);
+ // if (!registrations.Any())
+ // throw new KeyNotFoundException(name);
+ // if (registrations.Count() > 1)
+ // throw new InvalidOperationException(string.Format(Resources.MultipleViewsRegisteredForNavigationKey, name, string.Join(", ", registrations.Select(x => x.View.FullName))));
+
+ // return registrations.First().View;
+ //}
+}
diff --git a/src/Prism.Maui/Navigation/Builder/NavigationBuilder.cs b/src/Prism.Maui/Navigation/Builder/NavigationBuilder.cs
index 46ea390..4517c5e 100644
--- a/src/Prism.Maui/Navigation/Builder/NavigationBuilder.cs
+++ b/src/Prism.Maui/Navigation/Builder/NavigationBuilder.cs
@@ -1,6 +1,9 @@
-namespace Prism.Navigation.Builder;
+using Prism.Common;
+using Prism.Mvvm;
-internal class NavigationBuilder : INavigationBuilder
+namespace Prism.Navigation.Builder;
+
+internal class NavigationBuilder : INavigationBuilder, IRegistryAware
{
internal static readonly Uri RootUri = new Uri("app://prismapp.maui", UriKind.Absolute);
@@ -16,6 +19,10 @@ public NavigationBuilder(INavigationService navigationService)
_uriSegments = new List();
}
+ IViewRegistry IRegistryAware.Registry => ((IRegistryAware)_navigationService).Registry;
+
+ public IViewRegistry Registry { get; }
+
public INavigationBuilder AddNavigationSegment(string segmentName, Action configureSegment)
{
var builder = new SegmentBuilder(segmentName);
@@ -26,7 +33,7 @@ public INavigationBuilder AddNavigationSegment(string segmentName, Action configureSegment)
{
- var builder = new TabbedSegmentBuilder();
+ var builder = new TabbedSegmentBuilder(this);
configureSegment?.Invoke(builder);
_uriSegments.Add(builder);
return this;
diff --git a/src/Prism.Maui/Navigation/Builder/NavigationBuilderExtensions.cs b/src/Prism.Maui/Navigation/Builder/NavigationBuilderExtensions.cs
index fecf96f..e836728 100644
--- a/src/Prism.Maui/Navigation/Builder/NavigationBuilderExtensions.cs
+++ b/src/Prism.Maui/Navigation/Builder/NavigationBuilderExtensions.cs
@@ -1,4 +1,5 @@
-using Prism.Navigation.Builder;
+using Prism.Common;
+using Prism.Navigation.Builder;
namespace Prism.Navigation;
@@ -7,13 +8,16 @@ public static class NavigationBuilderExtensions
public static INavigationBuilder CreateBuilder(this INavigationService navigationService) =>
new NavigationBuilder(navigationService);
- internal static string GetNavigationKey()
+ internal static string GetNavigationKey(object builder)
{
var vmType = typeof(TViewModel);
if (vmType.IsAssignableFrom(typeof(VisualElement)))
throw new NavigationException(NavigationException.MvvmPatternBreak, typeof(TViewModel).Name);
- return NavigationRegistry.GetViewModelNavigationKey(vmType);
+ if (builder is not IRegistryAware registryAware)
+ throw new Exception("The builder does not implement IRegistryAware");
+
+ return registryAware.Registry.GetViewModelNavigationKey(vmType);
}
public static INavigationBuilder UseAbsoluteNavigation(this INavigationBuilder builder) =>
@@ -30,13 +34,13 @@ public static ICreateTabBuilder AddNavigationSegment(this ICreateTab
builder.AddNavigationSegment(b => { });
public static ICreateTabBuilder AddNavigationSegment(this ICreateTabBuilder builder, Action configureSegment) =>
- builder.AddNavigationSegment(GetNavigationKey(), configureSegment);
+ builder.AddNavigationSegment(GetNavigationKey(builder), configureSegment);
public static INavigationBuilder AddNavigationSegment(this INavigationBuilder builder) =>
builder.AddNavigationSegment(b => { });
public static INavigationBuilder AddNavigationSegment(this INavigationBuilder builder, Action configureSegment) =>
- builder.AddNavigationSegment(GetNavigationKey(), configureSegment);
+ builder.AddNavigationSegment(GetNavigationKey(builder), configureSegment);
public static INavigationBuilder AddNavigationSegment(this INavigationBuilder builder, bool useModalNavigation) =>
builder.AddNavigationSegment(b => b.UseModalNavigation(useModalNavigation));
@@ -47,12 +51,15 @@ public static INavigationBuilder AddNavigationPage(this INavigationBuilder build
public static INavigationBuilder AddNavigationPage(this INavigationBuilder builder, Action configureSegment)
{
- var registrationInfo = NavigationRegistry.Registrations
- .FirstOrDefault(x => x.View.IsAssignableTo(typeof(NavigationPage)));
- if (registrationInfo is null)
+ if (builder is not IRegistryAware registryAware)
+ throw new Exception("The builder does not implement IRegistryAware");
+
+ var registrations = registryAware.Registry.ViewsOfType(typeof(NavigationPage));
+ if (!registrations.Any())
throw new NavigationException(NavigationException.NoPageIsRegistered, nameof(NavigationPage));
- return builder.AddNavigationSegment(registrationInfo.Name, configureSegment);
+ var registration = registrations.Last();
+ return builder.AddNavigationSegment(registration.Name, configureSegment);
}
public static ICreateTabBuilder AddNavigationPage(this ICreateTabBuilder builder) =>
@@ -60,12 +67,15 @@ public static ICreateTabBuilder AddNavigationPage(this ICreateTabBuilder builder
public static ICreateTabBuilder AddNavigationPage(this ICreateTabBuilder builder, Action configureSegment)
{
- var registrationInfo = NavigationRegistry.Registrations
- .FirstOrDefault(x => x.View.IsAssignableTo(typeof(NavigationPage)));
- if (registrationInfo is null)
+ if (builder is not IRegistryAware registryAware)
+ throw new Exception("The builder does not implement IRegistryAware");
+
+ var registrations = registryAware.Registry.ViewsOfType(typeof(NavigationPage));
+ if (!registrations.Any())
throw new NavigationException(NavigationException.NoPageIsRegistered, nameof(NavigationPage));
- return builder.AddNavigationSegment(registrationInfo.Name, configureSegment);
+ var registration = registrations.Last();
+ return builder.AddNavigationSegment(registration.Name, configureSegment);
}
public static INavigationBuilder AddNavigationPage(this INavigationBuilder builder, bool useModalNavigation) =>
@@ -120,13 +130,13 @@ public static ITabbedSegmentBuilder CreateTab(this ITabbedSegmentBuilder builder
public static ITabbedSegmentBuilder CreateTab(this ITabbedSegmentBuilder builder)
{
- var navigationKey = GetNavigationKey();
+ var navigationKey = GetNavigationKey(builder);
return builder.CreateTab(navigationKey);
}
public static ITabbedSegmentBuilder SelectTab(this ITabbedSegmentBuilder builder)
{
- var navigationKey = GetNavigationKey();
+ var navigationKey = GetNavigationKey(builder);
return builder.SelectedTab(navigationKey);
}
diff --git a/src/Prism.Maui/Navigation/Builder/TabbedSegmentBuilder.cs b/src/Prism.Maui/Navigation/Builder/TabbedSegmentBuilder.cs
index 744f542..c684690 100644
--- a/src/Prism.Maui/Navigation/Builder/TabbedSegmentBuilder.cs
+++ b/src/Prism.Maui/Navigation/Builder/TabbedSegmentBuilder.cs
@@ -1,21 +1,31 @@
-namespace Prism.Navigation.Builder;
+using Prism.Common;
+using Prism.Mvvm;
-internal class TabbedSegmentBuilder : ITabbedSegmentBuilder, IConfigurableSegmentName, IUriSegment
+namespace Prism.Navigation.Builder;
+
+internal class TabbedSegmentBuilder : ITabbedSegmentBuilder, IConfigurableSegmentName, IUriSegment, IRegistryAware
{
private INavigationParameters _parameters { get; }
+ private INavigationBuilder _builder { get; }
- public TabbedSegmentBuilder()
+ public TabbedSegmentBuilder(INavigationBuilder builder)
{
+ _builder = builder;
_parameters = new NavigationParameters();
- var registrationInfo = NavigationRegistry.Registrations
- .FirstOrDefault(x => x.View.IsAssignableFrom(typeof(TabbedPage)));
- if (registrationInfo is null)
- throw new NavigationException(NavigationException.NoPageIsRegistered);
+ if (builder is not IRegistryAware registryAware)
+ throw new Exception("The builder does not implement IRegistryAware");
+
+ var registrations = registryAware.Registry.ViewsOfType(typeof(TabbedPage));
+ if (!registrations.Any())
+ throw new NavigationException(NavigationException.NoPageIsRegistered, nameof(TabbedPage));
- SegmentName = registrationInfo.Name;
+ var registration = registrations.Last();
+ SegmentName = registration.Name;
}
+ IViewRegistry IRegistryAware.Registry => ((IRegistryAware)_builder).Registry;
+
public string SegmentName { get; set; }
public string Segment => BuildSegment();
diff --git a/src/Prism.Maui/Navigation/INavigationRegistry.cs b/src/Prism.Maui/Navigation/INavigationRegistry.cs
new file mode 100644
index 0000000..df104e9
--- /dev/null
+++ b/src/Prism.Maui/Navigation/INavigationRegistry.cs
@@ -0,0 +1,5 @@
+using Prism.Mvvm;
+
+namespace Prism.Navigation;
+
+public interface INavigationRegistry : IViewRegistry { }
diff --git a/src/Prism.Maui/Navigation/NavigationRegistry.cs b/src/Prism.Maui/Navigation/NavigationRegistry.cs
index 5896b7a..e8d1e38 100644
--- a/src/Prism.Maui/Navigation/NavigationRegistry.cs
+++ b/src/Prism.Maui/Navigation/NavigationRegistry.cs
@@ -1,140 +1,53 @@
-using System.ComponentModel;
-using System.Data;
-using System.Text.RegularExpressions;
-using Prism.Behaviors;
+using Prism.Behaviors;
using Prism.Common;
using Prism.Ioc;
using Prism.Mvvm;
-using Prism.Properties;
+using Prism.Navigation.Xaml;
namespace Prism.Navigation;
-public static class NavigationRegistry
+internal class NavigationRegistry : ViewRegistryBase, INavigationRegistry
{
- private static readonly List _registrations = new ();
-
- internal static IEnumerable Registrations => _registrations;
-
- public static void Register(string name) =>
- Register(typeof(TView), typeof(TViewModel), name);
-
- public static void Register(Type viewType, Type viewModelType, string name)
+ public NavigationRegistry(IEnumerable registrations)
+ : base(ViewType.Page, registrations)
{
- if (_registrations.Any(x => x.Name == name))
- throw new DuplicateNameException($"A view with the name '{name}' has already been registered");
-
- var registration = new ViewRegistration
- {
- View = viewType,
- ViewModel = viewModelType,
- Name = name
- };
- _registrations.Add(registration);
}
- public static object CreateView(IContainerProvider container, string name)
+ protected override void ConfigureView(BindableObject bindable, IContainerProvider container)
{
- try
- {
- var registration = _registrations.FirstOrDefault(x => x.Name == name);
- if (registration is null)
- throw new KeyNotFoundException($"No view with the name '{name}' has been registered");
-
- var view = container.Resolve(registration.View) as BindableObject;
-
- view.SetValue(Xaml.Navigation.NavigationScopeProperty, container);
-
- if (view is Page page)
- {
- ConfigurePage(container, page);
- }
-
- if (view.BindingContext is not null)
- return view;
-
- if (registration.ViewModel is not null)
- view.SetValue(ViewModelLocator.ViewModelProperty, registration.ViewModel);
-
- ViewModelLocator.Autowire(view);
-
- return view;
- }
- catch (KeyNotFoundException)
- {
- throw;
- }
- catch (Exception ex)
- {
- throw new Exception($"Unable to create page '{name}'.", ex);
- }
+ ConfigurePage(container, bindable as Page);
}
- public static bool IsRegistered(string name) =>
- _registrations.Any(x => x.Name == name);
-
- public static Type GetPageType(string name)
- {
- var registrations = _registrations.Where(x => x.Name == name);
- if (!registrations.Any())
- throw new KeyNotFoundException(name);
- if (registrations.Count() > 1)
- throw new InvalidOperationException(string.Format(Resources.MultipleViewsRegisteredForNavigationKey, name, string.Join(", ", registrations.Select(x => x.View.FullName))));
-
- return registrations.First().View;
- }
-
- // To be used for the NavigationBuilder ViewModel Navigation Support
- [EditorBrowsable(EditorBrowsableState.Never)]
- public static string GetViewModelNavigationKey(Type viewModelType)
- {
- var registrations = _registrations.Where(x => x.ViewModel == viewModelType);
-
- if(!registrations.Any())
- {
- var names = new[]
- {
- Regex.Replace(viewModelType.Name, @"ViewModel$", string.Empty),
- Regex.Replace(viewModelType.Name, @"Model$", string.Empty),
- };
- registrations = _registrations.Where(x => names.Any(n => n == x.View.Name || x.Name == n));
- }
-
- if (registrations.Count() > 1)
- throw new InvalidOperationException($"Multiple Registrations were found for '{viewModelType.FullName}'");
- else if (registrations.Count() == 1)
- return registrations.First().Name;
-
- throw new InvalidOperationException($"No Registrations were found for '{viewModelType.FullName}'");
- }
-
- public static ViewRegistration GetPageNavigationInfo(Type viewType) =>
- _registrations.FirstOrDefault(x => x.View == viewType);
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public static void ClearRegistrationCache() => _registrations.Clear();
-
private static void ConfigurePage(IContainerProvider container, Page page)
{
- if(page is TabbedPage tabbed)
+ if (page is TabbedPage tabbed)
{
- foreach(var child in tabbed.Children)
+ foreach (var child in tabbed.Children)
{
var scope = container.CreateScope();
ConfigurePage(scope, child);
}
}
- else if(page is NavigationPage navPage && navPage.RootPage is not null)
+ else if (page is NavigationPage navPage && navPage.RootPage is not null)
{
var scope = container.CreateScope();
ConfigurePage(scope, navPage.RootPage);
}
- if (page.GetValue(Xaml.Navigation.NavigationScopeProperty) is null)
- page.SetValue(Xaml.Navigation.NavigationScopeProperty, container);
-
- container.Resolve().Page = page;
+ if (page.GetContainerProvider() is null)
+ page.SetContainerProvider(container);
- page.SetValue(Xaml.Navigation.NavigationServiceProperty, container.Resolve());
+ var accessor = container.Resolve();
+ if (accessor.Page is not null && accessor.Page != page)
+ {
+#if DEBUG
+ if (System.Diagnostics.Debugger.IsAttached)
+ System.Diagnostics.Debugger.Break();
+#endif
+ throw new NavigationException($"Invalid Scope provided. The current scope Page Accessor contains '{accessor.Page.GetType().FullName}', expected '{page.GetType().FullName}'.", page);
+ }
+ else if (accessor.Page is null)
+ accessor.Page = page;
var behaviorFactories = container.Resolve>();
foreach (var factory in behaviorFactories)
diff --git a/src/Prism.Maui/Navigation/PageNavigationService.cs b/src/Prism.Maui/Navigation/PageNavigationService.cs
index 578b833..40340b0 100644
--- a/src/Prism.Maui/Navigation/PageNavigationService.cs
+++ b/src/Prism.Maui/Navigation/PageNavigationService.cs
@@ -1,6 +1,7 @@
using Prism.Common;
using Prism.Events;
using Prism.Ioc;
+using Prism.Mvvm;
using Application = Microsoft.Maui.Controls.Application;
namespace Prism.Navigation;
@@ -8,7 +9,7 @@ namespace Prism.Navigation;
///
/// Provides page based navigation for ViewModels.
///
-public class PageNavigationService : INavigationService
+public class PageNavigationService : INavigationService, IRegistryAware
{
private static readonly SemaphoreSlim _semaphore = new (1, 1);
internal const string RemovePageRelativePath = "../";
@@ -37,18 +38,26 @@ protected Window Window
}
}
+ private readonly IViewRegistry _registry;
+ IViewRegistry IRegistryAware.Registry => _registry;
+
///
/// Constructs a new instance of the .
///
/// The that will be used to resolve pages for navigation.
/// The that will let us ensure the Application.MainPage is set.
/// The that will raise .
- public PageNavigationService(IContainerProvider container, IApplication application, IEventAggregator eventAggregator, IPageAccessor pageAccessor)
+ public PageNavigationService(IContainerProvider container,
+ IApplication application,
+ IEventAggregator eventAggregator,
+ IPageAccessor pageAccessor,
+ INavigationRegistry navigationRegistry)
{
_container = container;
_application = application;
_eventAggregator = eventAggregator;
_pageAccessor = pageAccessor;
+ _registry = navigationRegistry;
}
///
@@ -395,7 +404,7 @@ await DoNavigateAction(GetCurrentPage(), nextSegment, nextPage, parameters, asyn
protected virtual async Task ProcessNavigationForContentPage(Page currentPage, string nextSegment, Queue segments, INavigationParameters parameters, bool? useModalNavigation, bool animated)
{
- var nextPageType = NavigationRegistry.GetPageType(UriParsingHelper.GetSegmentName(nextSegment));
+ var nextPageType = _registry.GetViewType(UriParsingHelper.GetSegmentName(nextSegment));
bool useReverse = UseReverseNavigation(currentPage, nextPageType) && !(useModalNavigation.HasValue && useModalNavigation.Value);
if (!useReverse)
{
@@ -439,7 +448,7 @@ protected virtual async Task ProcessNavigationForNavigationPage(NavigationPage c
}
var topPage = currentPage.Navigation.NavigationStack.LastOrDefault();
- var nextPageType = NavigationRegistry.GetPageType(UriParsingHelper.GetSegmentName(nextSegment));
+ var nextPageType = _registry.GetViewType(UriParsingHelper.GetSegmentName(nextSegment));
if (topPage?.GetType() == nextPageType)
{
if (clearNavigationStack)
@@ -512,7 +521,7 @@ await DoNavigateAction(currentPage, nextSegment, nextPage, parameters, async ()
return;
}
- var nextSegmentType = NavigationRegistry.GetPageType(UriParsingHelper.GetSegmentName(nextSegment));
+ var nextSegmentType = _registry.GetViewType(UriParsingHelper.GetSegmentName(nextSegment));
//we must recreate the NavigationPage everytime or the transitions on iOS will not work properly, unless we meet the two scenarios below
bool detailIsNavPage = false;
@@ -531,7 +540,7 @@ await DoNavigateAction(currentPage, nextSegment, nextPage, parameters, async ()
{
//if we weren't forced to reuse the NavPage, then let's check the NavPage.CurrentPage against the next segment type as we don't want to recreate the entire nav stack
//just in case the user is trying to navigate to the same page which may be nested in a NavPage
- var nextPageType = NavigationRegistry.GetPageType(UriParsingHelper.GetSegmentName(segments.Peek()));
+ var nextPageType = _registry.GetViewType(UriParsingHelper.GetSegmentName(segments.Peek()));
var currentPageType = navPage.CurrentPage.GetType();
if (nextPageType == currentPageType)
{
@@ -679,7 +688,7 @@ protected virtual Page CreatePage(string segmentName)
try
{
var scope = _container.CreateScope();
- var page = (Page)NavigationRegistry.CreateView(scope, segmentName);
+ var page = (Page)_registry.CreateView(scope, segmentName);
if (page is null)
throw new NullReferenceException($"The resolved type for {segmentName} was null. You may be attempting to navigate to a Non-Page type");
@@ -692,9 +701,9 @@ protected virtual Page CreatePage(string segmentName)
throw;
else if(ex is KeyNotFoundException)
- throw new NavigationException(NavigationException.NoPageIsRegistered, _pageAccessor.Page, ex);
+ throw new NavigationException(NavigationException.NoPageIsRegistered, segmentName, ex);
- throw new NavigationException(NavigationException.ErrorCreatingPage, _pageAccessor.Page, ex);
+ throw new NavigationException(NavigationException.ErrorCreatingPage, segmentName, ex);
}
}
@@ -763,7 +772,7 @@ void ConfigureTabbedPage(TabbedPage tabbedPage, string segment)
TabbedPageSelectTab(tabbedPage, parameters);
}
- private static void SelectPageTab(Page page, INavigationParameters parameters)
+ private void SelectPageTab(Page page, INavigationParameters parameters)
{
if (page is TabbedPage tabbedPage)
{
@@ -771,12 +780,12 @@ private static void SelectPageTab(Page page, INavigationParameters parameters)
}
}
- private static void TabbedPageSelectTab(TabbedPage tabbedPage, INavigationParameters parameters)
+ private void TabbedPageSelectTab(TabbedPage tabbedPage, INavigationParameters parameters)
{
var selectedTab = parameters?.GetValue(KnownNavigationParameters.SelectedTab);
if (!string.IsNullOrWhiteSpace(selectedTab))
{
- var selectedTabType = NavigationRegistry.GetPageType(UriParsingHelper.GetSegmentName(selectedTab));
+ var selectedTabType = _registry.GetViewType(UriParsingHelper.GetSegmentName(selectedTab));
var childFound = false;
foreach (var child in tabbedPage.Children)
@@ -834,7 +843,7 @@ protected virtual async Task UseReverseNavigation(Page currentPage, string nextS
}
else
{
- var pageType = NavigationRegistry.GetPageType(UriParsingHelper.GetSegmentName(item));
+ var pageType = _registry.GetViewType(UriParsingHelper.GetSegmentName(item));
if (MvvmHelpers.IsSameOrSubclassOf(pageType))
{
illegalSegments.Enqueue(item);
diff --git a/src/Prism.Maui/Navigation/Xaml/Navigation.cs b/src/Prism.Maui/Navigation/Xaml/Navigation.cs
index 1d7a391..af4fdfb 100644
--- a/src/Prism.Maui/Navigation/Xaml/Navigation.cs
+++ b/src/Prism.Maui/Navigation/Xaml/Navigation.cs
@@ -1,4 +1,5 @@
using System.ComponentModel;
+using Prism.Common;
using Prism.Ioc;
namespace Prism.Navigation.Xaml;
@@ -8,22 +9,25 @@ namespace Prism.Navigation.Xaml;
///
public static class Navigation
{
- internal static readonly BindableProperty NavigationServiceProperty =
- BindableProperty.CreateAttached("NavigationService",
- typeof(INavigationService),
- typeof(Navigation),
- default(INavigationService));
+ internal const string PrismContainerProvider = nameof(PrismContainerProvider);
- internal static readonly BindableProperty NavigationScopeProperty =
- BindableProperty.CreateAttached("NavigationScope",
+ private static readonly BindableProperty NavigationScopeProperty =
+ BindableProperty.CreateAttached(PrismContainerProvider,
typeof(IContainerProvider),
typeof(Navigation),
default(IContainerProvider),
propertyChanged: OnNavigationScopeChanged);
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static readonly BindableProperty ChildViewsProperty =
+ BindableProperty.CreateAttached("ChildViews",
+ typeof(IEnumerable),
+ typeof(Navigation),
+ null);
+
private static void OnNavigationScopeChanged(BindableObject bindable, object oldValue, object newValue)
{
- if (oldValue == newValue)
+ if (bindable is not Page page || oldValue == newValue)
{
return;
}
@@ -36,6 +40,12 @@ private static void OnNavigationScopeChanged(BindableObject bindable, object old
if (newValue != null && newValue is IScopedProvider scopedProvider)
{
+ var accessor = scopedProvider.Resolve();
+ if (accessor.Page is null)
+ accessor.Page = page;
+ else if (accessor.Page != page)
+ throw new InvalidOperationException($"The Scoped Provider has already been assigned to another page. Expected: '{page.GetType().FullName}' - Found: '{accessor.Page.GetType().FullName}'.");
+
scopedProvider.IsAttached = true;
}
}
@@ -80,12 +90,41 @@ public static INavigationService GetNavigationService(Page page)
{
if (page == null) throw new ArgumentNullException(nameof(page));
- var container = page.GetValue(NavigationScopeProperty) as IContainerProvider;
- var navigationService = container.Resolve();
+ var container = page.GetContainerProvider();
+ return container.Resolve();
+ }
- return navigationService;
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static void SetContainerProvider(this BindableObject bindable, IContainerProvider container)
+ {
+ bindable.SetValue(NavigationScopeProperty, container);
}
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static IContainerProvider GetContainerProvider(this BindableObject bindable)
+ {
+ if (bindable is null)
+ return null;
+
+ var container = bindable.GetValue(NavigationScopeProperty) as IContainerProvider;
+ if (container is not null || bindable is Page)
+ return container;
+ else if (bindable is Element element && element.Parent is not null)
+ return GetContainerProvider(element.Parent);
+
+ return null;
+ }
+
+ internal static IEnumerable GetChildViews(this Page page)
+ {
+ var children = page.GetValue(ChildViewsProperty) as IEnumerable;
+ if (children is not null)
+ return children;
+
+ return Array.Empty();
+ }
+
+
internal static Action GetRaiseCanExecuteChangedInternal(BindableObject view) => (Action)view.GetValue(RaiseCanExecuteChangedInternalProperty);
internal static void SetRaiseCanExecuteChangedInternal(BindableObject view, Action value) => view.SetValue(RaiseCanExecuteChangedInternalProperty, value);
diff --git a/src/Prism.Maui/PrismAppBuilder.cs b/src/Prism.Maui/PrismAppBuilder.cs
index ce6f8a4..35218c4 100644
--- a/src/Prism.Maui/PrismAppBuilder.cs
+++ b/src/Prism.Maui/PrismAppBuilder.cs
@@ -7,6 +7,8 @@
using Prism.Modularity;
using Prism.Mvvm;
using Prism.Navigation;
+using Prism.Navigation.Xaml;
+using Prism.Regions;
using Prism.Regions.Adapters;
using Prism.Regions.Behaviors;
using Prism.Services;
@@ -73,18 +75,9 @@ internal static object DefaultViewModelLocator(object view, Type viewModelType)
if (view is not BindableObject bindable)
return null;
- var container = bindable.GetValue(Navigation.Xaml.Navigation.NavigationScopeProperty) as IContainerProvider;
+ var container = bindable.GetContainerProvider();
- var overrides = new List<(Type Type, object Instance)>();
- if (container.IsRegistered())
- {
- var resolver = container.Resolve();
- var resolverOverrides = resolver.GetOverrides();
- if (resolverOverrides.Any())
- overrides.AddRange(resolverOverrides);
- }
-
- return container.Resolve(viewModelType, overrides.ToArray());
+ return container.Resolve(viewModelType);
}
public PrismAppBuilder RegisterTypes(Action registerTypes)
@@ -110,13 +103,21 @@ internal void OnInitialized()
}
var app = _container.Resolve();
- if (!NavigationRegistry.IsRegistered(nameof(NavigationPage)))
+ var navRegistry = _container.Resolve();
+ if (!navRegistry.IsRegistered(nameof(NavigationPage)))
{
- NavigationRegistry.Register(typeof(PrismNavigationPage), null, nameof(NavigationPage));
- ((IContainerRegistry)_container).Register(typeof(PrismNavigationPage), () => new PrismNavigationPage());
+ var registry = _container as IContainerRegistry;
+ registry
+ .Register(() => new PrismNavigationPage())
+ .RegisterInstance(new ViewRegistration
+ {
+ Name = nameof(NavigationPage),
+ View = typeof(PrismNavigationPage),
+ Type = ViewType.Page
+ });
}
- if (!NavigationRegistry.IsRegistered(nameof(TabbedPage)))
+ if (!navRegistry.IsRegistered(nameof(TabbedPage)))
((IContainerRegistry)_container).RegisterForNavigation();
if (app is ILegacyPrismApplication prismApp)
@@ -142,7 +143,7 @@ public PrismAppBuilder ConfigureDefaultViewModelFactory(Func();
containerRegistry.RegisterScoped();
containerRegistry.RegisterScoped();
+ containerRegistry.Register();
containerRegistry.RegisterPageBehavior();
containerRegistry.RegisterPageBehavior();
diff --git a/src/Prism.Maui/Regions/Adapters/CarouselViewRegionAdapter.cs b/src/Prism.Maui/Regions/Adapters/CarouselViewRegionAdapter.cs
index 275de01..4eea8ec 100644
--- a/src/Prism.Maui/Regions/Adapters/CarouselViewRegionAdapter.cs
+++ b/src/Prism.Maui/Regions/Adapters/CarouselViewRegionAdapter.cs
@@ -2,6 +2,7 @@
using Prism.Behaviors;
using Prism.Common;
using Prism.Ioc;
+using Prism.Mvvm;
using Prism.Properties;
using Prism.Regions.Behaviors;
using Prism.Regions.Navigation;
@@ -112,8 +113,21 @@ private void OnCurrentItemChanged(object sender, CurrentItemChangedEventArgs e)
_region.Activate(newActiveView);
}
- var info = RegionNavigationRegistry.GetViewNavigationInfo(newActiveView.GetType());
- var context = new NavigationContext(_region.NavigationService, new Uri(info.Name, UriKind.RelativeOrAbsolute));
+ var name = newActiveView.GetValue(ViewModelLocator.NavigationNameProperty) as string;
+ if(string.IsNullOrEmpty(name))
+ {
+ var viewType = newActiveView.GetType();
+ var registry = _region.Container().Resolve();
+ var candidate = registry.ViewsOfType(viewType)
+ .Where(x => x.Type == ViewType.Region)
+ .FirstOrDefault(x => x.View == viewType);
+ if (candidate is null)
+ name = viewType.FullName;
+ else
+ name = candidate.Name;
+ }
+
+ var context = new NavigationContext(_region.NavigationService, new Uri(name, UriKind.RelativeOrAbsolute));
MvvmHelpers.OnNavigatedFrom(previousView, context);
MvvmHelpers.OnNavigatedTo(newActiveView, context);
diff --git a/src/Prism.Maui/Regions/Adapters/RegionAdapterBase.cs b/src/Prism.Maui/Regions/Adapters/RegionAdapterBase.cs
index 6d95880..120e653 100644
--- a/src/Prism.Maui/Regions/Adapters/RegionAdapterBase.cs
+++ b/src/Prism.Maui/Regions/Adapters/RegionAdapterBase.cs
@@ -1,5 +1,7 @@
using System.Globalization;
+using Prism.Extensions;
using Prism.Ioc;
+using Prism.Navigation.Xaml;
using Prism.Properties;
using Prism.Regions.Behaviors;
using XamlNavigation = Prism.Navigation.Xaml.Navigation;
@@ -34,9 +36,14 @@ protected RegionAdapterBase(IRegionBehaviorFactory regionBehaviorFactory)
/// The new instance of that the is bound to.
public IRegion Initialize(T regionTarget, string regionName)
{
- var container = regionTarget.GetValue(XamlNavigation.NavigationScopeProperty) as IContainerProvider;
+ var page = regionTarget.GetParentPage();
+ var container = regionTarget.GetContainerProvider();
IRegion region = CreateRegion(container);
region.Name = regionName ?? throw new ArgumentNullException(nameof(regionName));
+ if (region is ITargetAwareRegion taRegion)
+ taRegion.TargetElement = regionTarget;
+
+ page.SetBinding(XamlNavigation.ChildViewsProperty, new Binding(nameof(IRegion.ActiveViews), BindingMode.OneWay, source: region));
SetObservableRegionOnHostingControl(region, regionTarget);
diff --git a/src/Prism.Maui/Regions/AllActiveRegion.cs b/src/Prism.Maui/Regions/AllActiveRegion.cs
index f6502c9..e93b791 100644
--- a/src/Prism.Maui/Regions/AllActiveRegion.cs
+++ b/src/Prism.Maui/Regions/AllActiveRegion.cs
@@ -1,5 +1,5 @@
-using Prism.Ioc;
-using Prism.Properties;
+using Prism.Properties;
+using Prism.Regions.Navigation;
namespace Prism.Regions;
@@ -8,8 +8,8 @@ namespace Prism.Regions;
///
public class AllActiveRegion : Region
{
- public AllActiveRegion(IContainerProvider container)
- : base(container)
+ public AllActiveRegion(IRegionNavigationService regionNavigationService)
+ : base(regionNavigationService)
{
}
diff --git a/src/Prism.Maui/Regions/Behaviors/AutoPopulateRegionBehavior.cs b/src/Prism.Maui/Regions/Behaviors/AutoPopulateRegionBehavior.cs
index def74eb..4959c6c 100644
--- a/src/Prism.Maui/Regions/Behaviors/AutoPopulateRegionBehavior.cs
+++ b/src/Prism.Maui/Regions/Behaviors/AutoPopulateRegionBehavior.cs
@@ -56,7 +56,7 @@ private void StartPopulatingContent()
///
protected virtual IEnumerable