diff --git a/Toolkit.Avalonia/ContentDialogHandler.cs b/Toolkit.Avalonia/ContentDialogHandler.cs index da049b5..af56a81 100644 --- a/Toolkit.Avalonia/ContentDialogHandler.cs +++ b/Toolkit.Avalonia/ContentDialogHandler.cs @@ -9,7 +9,7 @@ public class ContentDialogHandler(IDispatcher dispatcher) : { public async Task Handle(NavigateEventArgs args) { - if (args.Region is ContentDialog contentDialog) + if (args.Template is ContentDialog contentDialog) { contentDialog.DataContext = args.Content; diff --git a/Toolkit.Avalonia/FrameHandler.cs b/Toolkit.Avalonia/FrameHandler.cs index d8d32ce..33497cb 100644 --- a/Toolkit.Avalonia/FrameHandler.cs +++ b/Toolkit.Avalonia/FrameHandler.cs @@ -40,7 +40,7 @@ public class FrameHandler : await deactivated.OnDeactivated(); } - if (content is not INavigationBackStack) + if (content is not IKeepAlive) { if (content is IDisposable disposable) { diff --git a/Toolkit.Foundation/ComponentBuilder.cs b/Toolkit.Foundation/ComponentBuilder.cs index b8da705..53a6a9b 100644 --- a/Toolkit.Foundation/ComponentBuilder.cs +++ b/Toolkit.Foundation/ComponentBuilder.cs @@ -37,7 +37,7 @@ public class ComponentBuilder : services.AddTransient(); services.AddTransient(); - services.AddTransient(); + services.AddTransient(); services.AddScoped(); services.AddTransient(); diff --git a/Toolkit.Foundation/ContentFactory.cs b/Toolkit.Foundation/ContentFactory.cs index f4359ae..80ec0f9 100644 --- a/Toolkit.Foundation/ContentFactory.cs +++ b/Toolkit.Foundation/ContentFactory.cs @@ -1,6 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; - -namespace Toolkit.Foundation; +namespace Toolkit.Foundation; public class ContentFactory(IMediator mediator, IServiceProvider provider, diff --git a/Toolkit.Foundation/DefaultHostBuilder.cs b/Toolkit.Foundation/DefaultHostBuilder.cs index 7ff3f95..5d7a70c 100644 --- a/Toolkit.Foundation/DefaultHostBuilder.cs +++ b/Toolkit.Foundation/DefaultHostBuilder.cs @@ -50,7 +50,7 @@ public class DefaultHostBuilder : services.AddScoped(); services.AddTransient(); - services.AddScoped(); + services.AddScoped(); services.AddSingleton(new NamedComponent("Root")); services.AddScoped(provider => new ComponentScopeCollection diff --git a/Toolkit.Foundation/IContentFactory.cs b/Toolkit.Foundation/IContentFactory.cs index 8597621..25c9ea9 100644 --- a/Toolkit.Foundation/IContentFactory.cs +++ b/Toolkit.Foundation/IContentFactory.cs @@ -3,6 +3,7 @@ namespace Toolkit.Foundation { public interface IContentFactory { - Task CreateAsync(IContentTemplateDescriptor descriptor, object[] resolvedArguments); + Task CreateAsync(IContentTemplateDescriptor descriptor, + object[] resolvedArguments); } } \ No newline at end of file diff --git a/Toolkit.Foundation/IKeepAlive.cs b/Toolkit.Foundation/IKeepAlive.cs new file mode 100644 index 0000000..82e6e0b --- /dev/null +++ b/Toolkit.Foundation/IKeepAlive.cs @@ -0,0 +1,3 @@ +namespace Toolkit.Foundation; + +public interface IKeepAlive; \ No newline at end of file diff --git a/Toolkit.Foundation/INavigation.cs b/Toolkit.Foundation/INavigation.cs index 3d63189..b47e408 100644 --- a/Toolkit.Foundation/INavigation.cs +++ b/Toolkit.Foundation/INavigation.cs @@ -2,5 +2,11 @@ public interface INavigation { - Type Type { get; set; } + void Navigate(string route, + object? sender = null, + object? region = null, + EventHandler? navigated = null, + IDictionary? parameters = null); + + void Back(object? region); } \ No newline at end of file diff --git a/Toolkit.Foundation/INavigationBackStack.cs b/Toolkit.Foundation/INavigationBackStack.cs deleted file mode 100644 index ca6c2da..0000000 --- a/Toolkit.Foundation/INavigationBackStack.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace Toolkit.Foundation; - -public interface INavigationBackStack; \ No newline at end of file diff --git a/Toolkit.Foundation/INavigationScope.cs b/Toolkit.Foundation/INavigationScope.cs deleted file mode 100644 index d8b2755..0000000 --- a/Toolkit.Foundation/INavigationScope.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Toolkit.Foundation; - -public interface INavigationScope -{ - void Navigate(string route, - object? sender = null, - object? region = null, - EventHandler? navigated = null, - IDictionary? parameters = null); - - void Back(object? region); -} \ No newline at end of file diff --git a/Toolkit.Foundation/NavigateBackHandler.cs b/Toolkit.Foundation/NavigateBackHandler.cs index fb56b64..4405242 100644 --- a/Toolkit.Foundation/NavigateBackHandler.cs +++ b/Toolkit.Foundation/NavigateBackHandler.cs @@ -10,8 +10,8 @@ public class NavigateBackHandler(IComponentScopeProvider provider) : if (provider.Get(args.Scope ?? "Root") is ComponentScopeDescriptor descriptor) { - if (descriptor?.Services?.GetService() is - INavigationScope navigationScope) + if (descriptor?.Services?.GetService() is + INavigation navigationScope) { navigationScope.Back(args.Context); } diff --git a/Toolkit.Foundation/NavigateHandler.cs b/Toolkit.Foundation/NavigateHandler.cs index c20db37..dd1be47 100644 --- a/Toolkit.Foundation/NavigateHandler.cs +++ b/Toolkit.Foundation/NavigateHandler.cs @@ -8,20 +8,20 @@ public class NavigateHandler(NamedComponent scope, { public Task Handle(NavigateEventArgs args) { - INavigationScope? navigationScope = null; + INavigation? navigationScope = null; if (args.Scope is "self" || args.Scope is "new") { if (args.Sender is IServiceProviderRequired requireServiceProvider) { if (args.Scope is "self") { - navigationScope = requireServiceProvider.Provider.GetRequiredService(); + navigationScope = requireServiceProvider.Provider.GetRequiredService(); } if (args.Scope is "new") { IServiceScope serviceScope = requireServiceProvider.Provider.CreateScope(); - navigationScope = serviceScope.ServiceProvider.GetRequiredService(); + navigationScope = serviceScope.ServiceProvider.GetRequiredService(); } } } @@ -29,7 +29,7 @@ public class NavigateHandler(NamedComponent scope, if (navigationScope is null) { ComponentScopeDescriptor? descriptor = componentScopeProvider.Get(args.Scope ?? scope.Name); - navigationScope = descriptor?.Services?.GetRequiredService(); + navigationScope = descriptor?.Services?.GetRequiredService(); } navigationScope?.Navigate(args.Route, args.Sender, diff --git a/Toolkit.Foundation/Navigation.cs b/Toolkit.Foundation/Navigation.cs index 6e6835a..5b0875c 100644 --- a/Toolkit.Foundation/Navigation.cs +++ b/Toolkit.Foundation/Navigation.cs @@ -1,7 +1,104 @@ -namespace Toolkit.Foundation; +using Microsoft.Extensions.DependencyInjection; -public record Navigation : +namespace Toolkit.Foundation; + +public class Navigation(IServiceProvider provider, + INavigationRegionProvider navigationRegionProvider, + IContentFactory contentFactory, + IPublisher publisher) : INavigation { - public required Type Type { get; set; } + public async void Navigate(string route, + object? sender = null, + object? region = null, + EventHandler? navigated = null, + IDictionary? parameters = null) + { + if (region is null) + { + return; + } + + string[] segments = route.Split('/'); + int segmentCount = segments.Length; + int currentSegmentIndex = 0; + + foreach (object segment in segments) + { + currentSegmentIndex++; + + if (provider.GetKeyedService(segment) + is IContentTemplateDescriptor descriptor) + { + Dictionary? arguments = parameters?.ToDictionary(x => x.Key, x => x.Value, StringComparer.InvariantCultureIgnoreCase) ?? []; + object[]? resolvedArguments = parameters is not null ? [.. descriptor.ContentType + .GetConstructors() + .FirstOrDefault()? + .GetParameters() + .Select(x => x?.Name is not null && arguments + .TryGetValue(x.Name, out object? argument) ? argument : default) + .Where(argument => argument is not null)] : []; + + if (provider.GetRequiredKeyedService(descriptor.TemplateType, descriptor.Key) + is object template) + { + if (region is not null) + { + switch (region) + { + case "self": + region = template; + break; + + default: + if (navigationRegionProvider.TryGet(region, out object? value)) + { + region = value; + } + + break; + } + } + + if (region is not null) + { + object? content = await contentFactory.CreateAsync(descriptor, resolvedArguments); + if (content is not null) + { + Type navigationType = region is Type type ? type : region.GetType(); + Type navigateEventType = typeof(NavigateEventArgs<>).MakeGenericType(navigationType); + + if (Activator.CreateInstance(navigateEventType, [region, template, content, sender, parameters]) + is object navigateEvent) + { + publisher.Publish(navigateEvent, navigationType.Name); + if (currentSegmentIndex == segmentCount) + { + navigated?.Invoke(this, EventArgs.Empty); + } + } + } + } + } + } + } + } + + public void Back(object? region) + { + if (region is not null) + { + navigationRegionProvider.TryGet(region, out region); + } + + if (region is not null) + { + Type navigationType = region is Type type ? type : region.GetType(); + Type navigateType = typeof(NavigateBackEventArgs<>).MakeGenericType(navigationType); + if (Activator.CreateInstance(navigateType, [region]) is object navigate) + { + publisher.Publish(navigate, navigationType.Name); + } + } + } } \ No newline at end of file diff --git a/Toolkit.Foundation/NavigationScope.cs b/Toolkit.Foundation/NavigationScope.cs deleted file mode 100644 index 31c173d..0000000 --- a/Toolkit.Foundation/NavigationScope.cs +++ /dev/null @@ -1,103 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; - -namespace Toolkit.Foundation; - -public class NavigationScope(IServiceProvider provider, - INavigationRegionProvider navigationRegionProvider, - IContentFactory contentFactory, - IPublisher publisher) : - INavigationScope -{ - public async void Navigate(string route, - object? sender = null, - object? region = null, - EventHandler? navigated = null, - IDictionary? parameters = null) - { - if (region is null) - { - return; - } - - string[] segments = route.Split('/'); - int segmentCount = segments.Length; - int currentSegmentIndex = 0; - - foreach (object segment in segments) - { - currentSegmentIndex++; - - if (provider.GetKeyedService(segment) - is IContentTemplateDescriptor descriptor) - { - Dictionary? arguments = parameters?.ToDictionary(x => x.Key, x => x.Value, StringComparer.InvariantCultureIgnoreCase) ?? []; - object[]? resolvedArguments = parameters is not null ? [.. descriptor.ContentType - .GetConstructors() - .FirstOrDefault()? - .GetParameters() - .Select(x => x?.Name is not null && arguments - .TryGetValue(x.Name, out object? argument) ? argument : default) - .Where(argument => argument is not null)] : []; - - if (provider.GetRequiredKeyedService(descriptor.TemplateType, descriptor.Key) - is object template) - { - if (region is not null) - { - switch (region) - { - case "self": - region = template; - break; - - default: - if (navigationRegionProvider.TryGet(region, out object? value)) - { - region = value; - } - - break; - } - } - - if (region is not null) - { - object? content = await contentFactory.CreateAsync(descriptor, resolvedArguments); - if (content is not null) - { - Type navigationType = region is Type type ? type : region.GetType(); - Type navigateEventType = typeof(NavigateEventArgs<>).MakeGenericType(navigationType); - if (Activator.CreateInstance(navigateEventType, [region, template, content, sender, parameters]) - is object navigateEvent) - { - publisher.Publish(navigateEvent, navigationType.Name); - if (currentSegmentIndex == segmentCount) - { - navigated?.Invoke(this, EventArgs.Empty); - } - } - } - } - } - } - } - } - - public void Back(object? region) - { - if (region is not null) - { - navigationRegionProvider.TryGet(region, out region); - } - - if (region is not null) - { - Type navigationType = region is Type type ? type : region.GetType(); - Type navigateType = typeof(NavigateBackEventArgs<>).MakeGenericType(navigationType); - if (Activator.CreateInstance(navigateType, [region]) is object navigate) - { - publisher.Publish(navigate, navigationType.Name); - } - } - } -} \ No newline at end of file