From b155f5c6e2336975574f96efb98eb0e5d7f572cb Mon Sep 17 00:00:00 2001 From: TheXamlGuy Date: Wed, 12 Jun 2024 23:04:22 +0100 Subject: [PATCH] wip --- Toolkit.Avalonia/ContentControlHandler.cs | 2 +- Toolkit.Avalonia/ContentDialogHandler.cs | 2 +- Toolkit.Avalonia/ContentTemplate.cs | 8 +- Toolkit.Avalonia/FrameHandler.cs | 2 +- .../IServiceCollectionExtensions.cs | 19 ++-- Toolkit.Foundation/AppService.cs | 4 +- Toolkit.Foundation/ChangedEventArgs.cs | 2 +- Toolkit.Foundation/CommandValueViewModel.cs | 2 +- Toolkit.Foundation/CommandViewModel.cs | 2 +- Toolkit.Foundation/ComponentBuilder.cs | 7 +- .../ComponentConfigurationViewModel.cs | 6 +- Toolkit.Foundation/ComponentHost.cs | 4 +- Toolkit.Foundation/ComponentInitializer.cs | 2 +- .../ConfigurationInitializer.cs | 2 +- Toolkit.Foundation/ContentFactory.cs | 46 +++++++++ .../ContentTemplateDescriptorProvider.cs | 16 ---- Toolkit.Foundation/DefaultHostBuilder.cs | 8 +- Toolkit.Foundation/IConfigurationChanged.cs | 2 +- Toolkit.Foundation/IContentFactory.cs | 8 ++ .../IContentTemplateDescriptorProvider.cs | 6 -- Toolkit.Foundation/IHostBuilderExtension.cs | 2 +- .../{IInitializer.cs => IInitialization.cs} | 4 +- Toolkit.Foundation/INavigationProvider.cs | 6 -- Toolkit.Foundation/IPostInitialization.cs | 6 ++ .../IServiceCollectionExtensions.cs | 30 +----- Toolkit.Foundation/IServiceFactory.cs | 3 + .../IServiceProviderExtensions.cs | 17 ++++ Toolkit.Foundation/ISubscriber.cs | 8 ++ Toolkit.Foundation/ISubscriberRequired.cs | 6 ++ Toolkit.Foundation/ISubscription.cs | 8 -- Toolkit.Foundation/ISubscriptionRequired.cs | 6 -- Toolkit.Foundation/NavigationProvider.cs | 16 ---- .../NavigationRegionProvider.cs | 6 +- Toolkit.Foundation/NavigationScope.cs | 63 ++++--------- .../NavigationTargetAttribute.cs | 8 -- Toolkit.Foundation/Observable.cs | 59 ++++++------ Toolkit.Foundation/ObservableCollection.cs | 94 ++++++++++++------- Toolkit.Foundation/ServiceFactory.cs | 9 ++ .../{Subscription.cs => Subscriber.cs} | 8 +- Toolkit.Foundation/ValueViewModel.cs | 2 +- 40 files changed, 262 insertions(+), 249 deletions(-) create mode 100644 Toolkit.Foundation/ContentFactory.cs delete mode 100644 Toolkit.Foundation/ContentTemplateDescriptorProvider.cs create mode 100644 Toolkit.Foundation/IContentFactory.cs delete mode 100644 Toolkit.Foundation/IContentTemplateDescriptorProvider.cs rename Toolkit.Foundation/{IInitializer.cs => IInitialization.cs} (56%) delete mode 100644 Toolkit.Foundation/INavigationProvider.cs create mode 100644 Toolkit.Foundation/IPostInitialization.cs create mode 100644 Toolkit.Foundation/IServiceProviderExtensions.cs create mode 100644 Toolkit.Foundation/ISubscriber.cs create mode 100644 Toolkit.Foundation/ISubscriberRequired.cs delete mode 100644 Toolkit.Foundation/ISubscription.cs delete mode 100644 Toolkit.Foundation/ISubscriptionRequired.cs delete mode 100644 Toolkit.Foundation/NavigationProvider.cs delete mode 100644 Toolkit.Foundation/NavigationTargetAttribute.cs rename Toolkit.Foundation/{Subscription.cs => Subscriber.cs} (96%) diff --git a/Toolkit.Avalonia/ContentControlHandler.cs b/Toolkit.Avalonia/ContentControlHandler.cs index 912fc19..a71c8d0 100644 --- a/Toolkit.Avalonia/ContentControlHandler.cs +++ b/Toolkit.Avalonia/ContentControlHandler.cs @@ -19,7 +19,7 @@ public class ContentControlHandler : control.Loaded -= HandleLoaded; if (control.DataContext is object content) { - if (content is IInitializer initializer) + if (content is IInitialization initializer) { await initializer.Initialize(); } diff --git a/Toolkit.Avalonia/ContentDialogHandler.cs b/Toolkit.Avalonia/ContentDialogHandler.cs index ccaae57..d4f76bb 100644 --- a/Toolkit.Avalonia/ContentDialogHandler.cs +++ b/Toolkit.Avalonia/ContentDialogHandler.cs @@ -129,7 +129,7 @@ public class ContentDialogHandler(IDispatcher dispatcher) : // A hack to wait for the dialog to finish loading up to make it appear more responsive await Task.Delay(250); - if (content is IInitializer initializer) + if (content is IInitialization initializer) { await initializer.Initialize(); } diff --git a/Toolkit.Avalonia/ContentTemplate.cs b/Toolkit.Avalonia/ContentTemplate.cs index 6e60b93..73ac15f 100644 --- a/Toolkit.Avalonia/ContentTemplate.cs +++ b/Toolkit.Avalonia/ContentTemplate.cs @@ -16,10 +16,10 @@ public class ContentTemplate : { if (observableViewModel.Provider is IServiceProvider provider) { - IContentTemplateDescriptorProvider? contentTemplateProvider = provider.GetService(); - INavigationRegion? viewModelContentBinder = provider.GetService(); + Type itemType = item.GetType(); - if (contentTemplateProvider?.Get(item.GetType().Name) is IContentTemplateDescriptor descriptor) + if (provider.GetRequiredKeyedService(itemType.Name.Replace("ViewModel", "")) + is IContentTemplateDescriptor descriptor) { if (provider.GetRequiredKeyedService(descriptor.TemplateType, descriptor.Key) is Control control) { @@ -28,7 +28,7 @@ public class ContentTemplate : control.Loaded -= HandleLoaded; if (control.DataContext is object content) { - if (content is IInitializer initializer) + if (content is IInitialization initializer) { await initializer.Initialize(); } diff --git a/Toolkit.Avalonia/FrameHandler.cs b/Toolkit.Avalonia/FrameHandler.cs index e6c4eab..59d1bba 100644 --- a/Toolkit.Avalonia/FrameHandler.cs +++ b/Toolkit.Avalonia/FrameHandler.cs @@ -72,7 +72,7 @@ public class FrameHandler : sender.AddHandler(Frame.NavigatingFromEvent, HandleNavigatingFrom); if (sender.DataContext is object content) { - if (content is IInitializer initializer) + if (content is IInitialization initializer) { await initializer.Initialize(); } diff --git a/Toolkit.Avalonia/IServiceCollectionExtensions.cs b/Toolkit.Avalonia/IServiceCollectionExtensions.cs index 737a798..b7996f2 100644 --- a/Toolkit.Avalonia/IServiceCollectionExtensions.cs +++ b/Toolkit.Avalonia/IServiceCollectionExtensions.cs @@ -3,6 +3,7 @@ using Avalonia.Controls.ApplicationLifetimes; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Toolkit.Foundation; +using Toolkit.UI.Controls.Avalonia; namespace Toolkit.Avalonia; @@ -128,11 +129,11 @@ public static class IServiceCollectionExtensions services.AddTransient(); services.AddTransient(); - services.AddNavigateHandler(); - services.AddNavigateHandler(); - services.AddNavigateHandler(); - services.AddNavigateHandler(); - services.AddNavigateHandler(); + services.AddHandler(nameof(IClassicDesktopStyleApplicationLifetime)); + services.AddHandler(nameof(ISingleViewApplicationLifetime)); + services.AddHandler(nameof(ContentControl)); + services.AddHandler(nameof(Frame)); + services.AddHandler(nameof(ContentDialog)); services.AddScoped(provider => new NavigationRegionCollection { @@ -144,15 +145,13 @@ public static class IServiceCollectionExtensions new ProxyServiceCollection(services => { services.AddSingleton(provider.GetRequiredService()); - - services.AddTransient(); services.AddTransient(); services.AddTransient(); - services.AddNavigateHandler(); - services.AddNavigateHandler(); - services.AddNavigateHandler(); + services.AddHandler(nameof(ContentControl)); + services.AddHandler(nameof(Frame)); + services.AddHandler(nameof(ContentDialog)); }))); return services; diff --git a/Toolkit.Foundation/AppService.cs b/Toolkit.Foundation/AppService.cs index 5504039..dd3f5e4 100644 --- a/Toolkit.Foundation/AppService.cs +++ b/Toolkit.Foundation/AppService.cs @@ -2,13 +2,13 @@ namespace Toolkit.Foundation; -public class AppService(IEnumerable initializers, +public class AppService(IEnumerable initializers, IPublisher publisher) : IHostedService { public async Task StartAsync(CancellationToken cancellationToken) { - foreach (IInitializer initializer in initializers) + foreach (IInitialization initializer in initializers) { await initializer.Initialize(); } diff --git a/Toolkit.Foundation/ChangedEventArgs.cs b/Toolkit.Foundation/ChangedEventArgs.cs index 5e6c1c7..85c75a3 100644 --- a/Toolkit.Foundation/ChangedEventArgs.cs +++ b/Toolkit.Foundation/ChangedEventArgs.cs @@ -1,3 +1,3 @@ namespace Toolkit.Foundation; -public record ChangedEventArgs(TSender? Sender = default); \ No newline at end of file +public record ChangedEventArgs(TSender? Sender = default); diff --git a/Toolkit.Foundation/CommandValueViewModel.cs b/Toolkit.Foundation/CommandValueViewModel.cs index ffe6c82..dd8bbb4 100644 --- a/Toolkit.Foundation/CommandValueViewModel.cs +++ b/Toolkit.Foundation/CommandValueViewModel.cs @@ -6,7 +6,7 @@ public partial class CommandValueViewModel(IServiceProvider provider, IServiceFactory factory, IMediator mediator, IPublisher publisher, - ISubscription subscriber, + ISubscriber subscriber, IDisposer disposer) : ValueViewModel(provider, factory, mediator, publisher, subscriber, disposer) { diff --git a/Toolkit.Foundation/CommandViewModel.cs b/Toolkit.Foundation/CommandViewModel.cs index 6022cbf..2b384b5 100644 --- a/Toolkit.Foundation/CommandViewModel.cs +++ b/Toolkit.Foundation/CommandViewModel.cs @@ -6,7 +6,7 @@ public partial class CommandViewModel(IServiceProvider provider, IServiceFactory factory, IMediator mediator, IPublisher publisher, - ISubscription subscriber, + ISubscriber subscriber, IDisposer disposer) : Observable(provider, factory, mediator, publisher, subscriber, disposer) { diff --git a/Toolkit.Foundation/ComponentBuilder.cs b/Toolkit.Foundation/ComponentBuilder.cs index 3c199c8..b8da705 100644 --- a/Toolkit.Foundation/ComponentBuilder.cs +++ b/Toolkit.Foundation/ComponentBuilder.cs @@ -32,14 +32,13 @@ public class ComponentBuilder : services.AddScoped(); services.AddTransient(); - services.AddScoped(); - + services.AddScoped(); services.AddTransient(); - services.AddTransient(); + + services.AddTransient(); services.AddTransient(); - services.AddTransient(); services.AddScoped(); services.AddTransient(); diff --git a/Toolkit.Foundation/ComponentConfigurationViewModel.cs b/Toolkit.Foundation/ComponentConfigurationViewModel.cs index d9a810b..45ac4f9 100644 --- a/Toolkit.Foundation/ComponentConfigurationViewModel.cs +++ b/Toolkit.Foundation/ComponentConfigurationViewModel.cs @@ -12,7 +12,7 @@ public partial class ComponentConfigurationViewModel initializers, + IEnumerable initializers, IEnumerable hostedServices) : IComponentHost { @@ -21,7 +21,7 @@ public class ComponentHost(IServiceProvider services, public async Task StartAsync(CancellationToken cancellationToken = default) { - foreach (IInitializer initializer in initializers) + foreach (IInitialization initializer in initializers) { await initializer.Initialize(); } diff --git a/Toolkit.Foundation/ComponentInitializer.cs b/Toolkit.Foundation/ComponentInitializer.cs index 768e780..f5c183e 100644 --- a/Toolkit.Foundation/ComponentInitializer.cs +++ b/Toolkit.Foundation/ComponentInitializer.cs @@ -7,7 +7,7 @@ public class ComponentInitializer(IEnumerable components, IComponentHostCollection hosts, IComponentScopeCollection scopes, IServiceProvider provider) : - IInitializer + IInitialization { public async Task Initialize() { diff --git a/Toolkit.Foundation/ConfigurationInitializer.cs b/Toolkit.Foundation/ConfigurationInitializer.cs index 1d033b8..c17b03c 100644 --- a/Toolkit.Foundation/ConfigurationInitializer.cs +++ b/Toolkit.Foundation/ConfigurationInitializer.cs @@ -5,7 +5,7 @@ public class ConfigurationInitializer(IConfigurationReader factory, IPublisher publisher) : IConfigurationInitializer, - IInitializer + IInitialization where TConfiguration : class { diff --git a/Toolkit.Foundation/ContentFactory.cs b/Toolkit.Foundation/ContentFactory.cs new file mode 100644 index 0000000..cfc5722 --- /dev/null +++ b/Toolkit.Foundation/ContentFactory.cs @@ -0,0 +1,46 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace Toolkit.Foundation; + +public class ContentFactory(IMediator mediator, + IServiceProvider provider, + IServiceFactory factory) : IContentFactory +{ + public async Task CreateAsync(IContentTemplateDescriptor descriptor, + object[] parameters) + { + Type createEventType = typeof(CreateEventArgs<>).MakeGenericType(descriptor.ContentType); + + object? content = null; + if (Activator.CreateInstance(createEventType, [null, parameters]) is object createEvent) + { + content = await mediator.Handle(descriptor.ContentType, createEvent, descriptor.Key); + } + + if (content is null) + { + if (parameters is { Length: > 0 }) + { + content = factory.Create(descriptor.ContentType, args => + { + if (args is IPostInitialization initialization) + { + initialization.PostInitialize(); + } + }, parameters); + } + else + { + content = provider.GetRequiredKeyedService(descriptor.ContentType, args => + { + if (args is IPostInitialization initialization) + { + initialization.PostInitialize(); + } + }, descriptor.Key); + } + } + + return content; + } +} diff --git a/Toolkit.Foundation/ContentTemplateDescriptorProvider.cs b/Toolkit.Foundation/ContentTemplateDescriptorProvider.cs deleted file mode 100644 index fd30799..0000000 --- a/Toolkit.Foundation/ContentTemplateDescriptorProvider.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Toolkit.Foundation; - -public class ContentTemplateDescriptorProvider(IEnumerable contentTemplates) : - IContentTemplateDescriptorProvider -{ - public IContentTemplateDescriptor? Get(object key) - { - if (contentTemplates.FirstOrDefault(x => x.Key.Equals(key) || x.Key.Equals($"{key}".Replace("ViewModel", ""))) - is IContentTemplateDescriptor viewModelTemplate) - { - return viewModelTemplate; - } - - return default; - } -} \ No newline at end of file diff --git a/Toolkit.Foundation/DefaultHostBuilder.cs b/Toolkit.Foundation/DefaultHostBuilder.cs index ee5c1cd..7ff3f95 100644 --- a/Toolkit.Foundation/DefaultHostBuilder.cs +++ b/Toolkit.Foundation/DefaultHostBuilder.cs @@ -29,9 +29,9 @@ public class DefaultHostBuilder : services.AddScoped(); services.AddTransient(); - services.AddTransient(); + services.AddTransient(); - services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); @@ -45,9 +45,7 @@ public class DefaultHostBuilder : services.AddScoped>(provider => new ProxyService(provider.GetRequiredService())); - services.AddTransient(); - - services.AddTransient(); + services.AddTransient(); services.AddScoped(); services.AddTransient(); diff --git a/Toolkit.Foundation/IConfigurationChanged.cs b/Toolkit.Foundation/IConfigurationChanged.cs index d0f8eee..3a436e7 100644 --- a/Toolkit.Foundation/IConfigurationChanged.cs +++ b/Toolkit.Foundation/IConfigurationChanged.cs @@ -1,4 +1,4 @@ namespace Toolkit.Foundation; public interface IConfigurationChanged : - IInitializer; \ No newline at end of file + IInitialization; \ No newline at end of file diff --git a/Toolkit.Foundation/IContentFactory.cs b/Toolkit.Foundation/IContentFactory.cs new file mode 100644 index 0000000..8597621 --- /dev/null +++ b/Toolkit.Foundation/IContentFactory.cs @@ -0,0 +1,8 @@ + +namespace Toolkit.Foundation +{ + public interface IContentFactory + { + Task CreateAsync(IContentTemplateDescriptor descriptor, object[] resolvedArguments); + } +} \ No newline at end of file diff --git a/Toolkit.Foundation/IContentTemplateDescriptorProvider.cs b/Toolkit.Foundation/IContentTemplateDescriptorProvider.cs deleted file mode 100644 index aa0da56..0000000 --- a/Toolkit.Foundation/IContentTemplateDescriptorProvider.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Toolkit.Foundation; - -public interface IContentTemplateDescriptorProvider -{ - IContentTemplateDescriptor? Get(object key); -} \ No newline at end of file diff --git a/Toolkit.Foundation/IHostBuilderExtension.cs b/Toolkit.Foundation/IHostBuilderExtension.cs index 9bb8653..93a20d4 100644 --- a/Toolkit.Foundation/IHostBuilderExtension.cs +++ b/Toolkit.Foundation/IHostBuilderExtension.cs @@ -156,7 +156,7 @@ public static class IHostBuilderExtension services.TryAddKeyedTransient>(section, (provider, key) => new ConfigurationFactory(() => defaultConfiguration ?? provider.GetRequiredKeyedService(key))); - services.AddTransient>(provider => + services.AddTransient>(provider => new ConfigurationInitializer(provider.GetRequiredKeyedService>(section), provider.GetRequiredKeyedService>(section), provider.GetRequiredKeyedService>(section), diff --git a/Toolkit.Foundation/IInitializer.cs b/Toolkit.Foundation/IInitialization.cs similarity index 56% rename from Toolkit.Foundation/IInitializer.cs rename to Toolkit.Foundation/IInitialization.cs index 1f803f6..4c8c3b2 100644 --- a/Toolkit.Foundation/IInitializer.cs +++ b/Toolkit.Foundation/IInitialization.cs @@ -1,11 +1,11 @@ namespace Toolkit.Foundation; -public interface IInitializer +public interface IInitialization { Task Initialize(); } -public interface IInitializer +public interface IInitialization { Task Initialize(); } \ No newline at end of file diff --git a/Toolkit.Foundation/INavigationProvider.cs b/Toolkit.Foundation/INavigationProvider.cs deleted file mode 100644 index 227bb91..0000000 --- a/Toolkit.Foundation/INavigationProvider.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Toolkit.Foundation; - -public interface INavigationProvider -{ - INavigation? Get(Type type); -} \ No newline at end of file diff --git a/Toolkit.Foundation/IPostInitialization.cs b/Toolkit.Foundation/IPostInitialization.cs new file mode 100644 index 0000000..9231dda --- /dev/null +++ b/Toolkit.Foundation/IPostInitialization.cs @@ -0,0 +1,6 @@ +namespace Toolkit.Foundation; + +public interface IPostInitialization +{ + void PostInitialize(); +} \ No newline at end of file diff --git a/Toolkit.Foundation/IServiceCollectionExtensions.cs b/Toolkit.Foundation/IServiceCollectionExtensions.cs index 73814e3..2679438 100644 --- a/Toolkit.Foundation/IServiceCollectionExtensions.cs +++ b/Toolkit.Foundation/IServiceCollectionExtensions.cs @@ -1,8 +1,6 @@ using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; namespace Toolkit.Foundation; - public static class IServiceCollectionExtensions { public static IServiceCollection AddCache(this IServiceCollection services) @@ -132,31 +130,9 @@ public static class IServiceCollectionExtensions public static IServiceCollection AddInitializer(this IServiceCollection services) where TInitializer : class, - IInitializer + IInitialization { - services.AddTransient(); - return services; - } - - public static IServiceCollection AddNavigateHandler(this IServiceCollection services) - where THandler : INavigateHandler, - IHandler - { - IEnumerable contracts = typeof(THandler).GetInterfaces() - .Where(x => x.Name == typeof(INavigateHandler<>).Name || x.Name == typeof(INavigateBackHandler<>).Name); - - foreach (Type contract in contracts) - { - if (contract.GetGenericArguments() is { Length: 1 } arguments) - { - services.AddTransient(provider => new Navigation - { - Type = arguments[0] - }); - } - } - - services.AddHandler(); + services.AddTransient(); return services; } @@ -205,7 +181,7 @@ public static class IServiceCollectionExtensions services.Add(new ServiceDescriptor(viewType, key, viewType, serviceLifetime)); - services.AddTransient(provider => + services.AddKeyedTransient(key, (provider, _) => new ContentTemplateDescriptor(key, viewModelType, viewType, parameters)); return services; diff --git a/Toolkit.Foundation/IServiceFactory.cs b/Toolkit.Foundation/IServiceFactory.cs index 5cf1845..2e0f420 100644 --- a/Toolkit.Foundation/IServiceFactory.cs +++ b/Toolkit.Foundation/IServiceFactory.cs @@ -7,5 +7,8 @@ public interface IServiceFactory TService Create(Action serviceDelegate, params object?[]? parameters); + object Create(Type type, Action serviceDelegate, + params object?[]? parameters); + TService Create(params object?[]? parameters); } \ No newline at end of file diff --git a/Toolkit.Foundation/IServiceProviderExtensions.cs b/Toolkit.Foundation/IServiceProviderExtensions.cs new file mode 100644 index 0000000..b32a901 --- /dev/null +++ b/Toolkit.Foundation/IServiceProviderExtensions.cs @@ -0,0 +1,17 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace Toolkit.Foundation; + +public static class IServiceProviderExtensions +{ + public static object GetRequiredKeyedService(this IServiceProvider provider, + Type serviceType, + Action serviceDelegate, + object? serviceKey) + { + object service = provider.GetRequiredKeyedService(serviceType, serviceKey); + serviceDelegate.Invoke(service); + + return service; + } +} diff --git a/Toolkit.Foundation/ISubscriber.cs b/Toolkit.Foundation/ISubscriber.cs new file mode 100644 index 0000000..aada57f --- /dev/null +++ b/Toolkit.Foundation/ISubscriber.cs @@ -0,0 +1,8 @@ +namespace Toolkit.Foundation; + +public interface ISubscriber +{ + void Subscribe(object subscriber); + + void Unsubscribe(object subscriber); +} \ No newline at end of file diff --git a/Toolkit.Foundation/ISubscriberRequired.cs b/Toolkit.Foundation/ISubscriberRequired.cs new file mode 100644 index 0000000..7a41b2b --- /dev/null +++ b/Toolkit.Foundation/ISubscriberRequired.cs @@ -0,0 +1,6 @@ +namespace Toolkit.Foundation; + +public interface ISubscriberRequired +{ + ISubscriber Subscription { get; } +} \ No newline at end of file diff --git a/Toolkit.Foundation/ISubscription.cs b/Toolkit.Foundation/ISubscription.cs deleted file mode 100644 index 858c85d..0000000 --- a/Toolkit.Foundation/ISubscription.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Toolkit.Foundation; - -public interface ISubscription -{ - void Add(object subscriber); - - void Remove(object subscriber); -} \ No newline at end of file diff --git a/Toolkit.Foundation/ISubscriptionRequired.cs b/Toolkit.Foundation/ISubscriptionRequired.cs deleted file mode 100644 index 726cdd7..0000000 --- a/Toolkit.Foundation/ISubscriptionRequired.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Toolkit.Foundation; - -public interface ISubscriptionRequired -{ - ISubscription Subscription { get; } -} \ No newline at end of file diff --git a/Toolkit.Foundation/NavigationProvider.cs b/Toolkit.Foundation/NavigationProvider.cs deleted file mode 100644 index 8a23026..0000000 --- a/Toolkit.Foundation/NavigationProvider.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Toolkit.Foundation; - -public class NavigationProvider(IEnumerable navigations) : - INavigationProvider -{ - public INavigation? Get(Type type) - { - if (navigations.FirstOrDefault(x => type == x.Type || - type.BaseType == x.Type) is INavigation navigation) - { - return navigation; - } - - return default; - } -} \ No newline at end of file diff --git a/Toolkit.Foundation/NavigationRegionProvider.cs b/Toolkit.Foundation/NavigationRegionProvider.cs index 9a5d7f0..eeebceb 100644 --- a/Toolkit.Foundation/NavigationRegionProvider.cs +++ b/Toolkit.Foundation/NavigationRegionProvider.cs @@ -1,15 +1,15 @@ namespace Toolkit.Foundation; -public class NavigationRegionProvider(INavigationRegionCollection contexts) : +public class NavigationRegionProvider(INavigationRegionCollection collection) : INavigationRegionProvider { public object? Get(object key) => - contexts.TryGetValue(key, out object? target) ? target : default; + collection.TryGetValue(key, out object? target) ? target : default; public bool TryGet(object name, out object? value) { - if (contexts.TryGetValue(name, + if (collection.TryGetValue(name, out object? target)) { value = target; diff --git a/Toolkit.Foundation/NavigationScope.cs b/Toolkit.Foundation/NavigationScope.cs index 2c1f9cf..c124928 100644 --- a/Toolkit.Foundation/NavigationScope.cs +++ b/Toolkit.Foundation/NavigationScope.cs @@ -2,13 +2,10 @@ namespace Toolkit.Foundation; -public class NavigationScope(IPublisher publisher, - IMediator mediator, - IServiceProvider provider, - IServiceFactory factory, - INavigationProvider navigationProvider, +public class NavigationScope(IServiceProvider provider, INavigationRegionProvider navigationRegionProvider, - IContentTemplateDescriptorProvider contentTemplateDescriptorProvider) : + IContentFactory contentFactory, + IPublisher publisher) : INavigationScope { public async void Navigate(string route, @@ -30,7 +27,7 @@ public class NavigationScope(IPublisher publisher, { currentSegmentIndex++; - if (contentTemplateDescriptorProvider.Get(segment) + if (provider.GetKeyedService(segment) is IContentTemplateDescriptor descriptor) { Dictionary? arguments = parameters?.ToDictionary(x => x.Key, x => x.Value, StringComparer.InvariantCultureIgnoreCase) ?? []; @@ -42,14 +39,15 @@ public class NavigationScope(IPublisher publisher, .TryGetValue(x.Name, out object? argument) ? argument : default) .Where(argument => argument is not null)] : []; - if (provider.GetRequiredKeyedService(descriptor.TemplateType, segment) is object view) + if (provider.GetRequiredKeyedService(descriptor.TemplateType, descriptor.Key) + is object template) { if (region is not null) { switch (region) { case "self": - region = view; + region = template; break; default: @@ -64,38 +62,18 @@ public class NavigationScope(IPublisher publisher, if (region is not null) { - Type createEventType = typeof(CreateEventArgs<>).MakeGenericType(descriptor.ContentType); - - object? content = null; - if (Activator.CreateInstance(createEventType, [null, resolvedArguments]) is object createEvent) - { - content = await mediator.Handle(descriptor.ContentType, createEvent, descriptor.Key); - } - - if (content is null) - { - if (resolvedArguments is { Length: > 0 }) - { - content = factory.Create(descriptor.ContentType, resolvedArguments); - } - else - { - content = provider.GetRequiredKeyedService(descriptor.ContentType, segment); - } - } - + object? content = await contentFactory.CreateAsync(descriptor, resolvedArguments); if (content is not null) { - if (navigationProvider.Get(region is Type type ? type : region.GetType()) is INavigation navigation) + 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) { - Type navigateEventType = typeof(NavigateEventArgs<>).MakeGenericType(navigation.Type); - if (Activator.CreateInstance(navigateEventType, [region, view, content, sender, parameters]) is object navigateEvent) + publisher.Publish(navigateEvent, navigationType.Name); + if (currentSegmentIndex == segmentCount) { - publisher.Publish(navigateEvent); - if (currentSegmentIndex == segmentCount) - { - navigated?.Invoke(this, EventArgs.Empty); - } + navigated?.Invoke(this, EventArgs.Empty); } } } @@ -114,14 +92,11 @@ public class NavigationScope(IPublisher publisher, if (region is not null) { - if (navigationProvider.Get(region is Type type ? type : region.GetType()) - is INavigation navigation) + Type navigationType = region is Type type ? type : region.GetType(); + Type navigateType = typeof(NavigateBackEventArgs<>).MakeGenericType(navigationType); + if (Activator.CreateInstance(navigateType, [region]) is object navigate) { - Type navigateType = typeof(NavigateBackEventArgs<>).MakeGenericType(navigation.Type); - if (Activator.CreateInstance(navigateType, [region]) is object navigate) - { - publisher.Publish(navigate); - } + publisher.Publish(navigate); } } } diff --git a/Toolkit.Foundation/NavigationTargetAttribute.cs b/Toolkit.Foundation/NavigationTargetAttribute.cs deleted file mode 100644 index 4529d86..0000000 --- a/Toolkit.Foundation/NavigationTargetAttribute.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Toolkit.Foundation; - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)] -public class NavigationTargetAttribute(string name) : - Attribute -{ - public string Name => name; -} \ No newline at end of file diff --git a/Toolkit.Foundation/Observable.cs b/Toolkit.Foundation/Observable.cs index 54ead02..b8788d5 100644 --- a/Toolkit.Foundation/Observable.cs +++ b/Toolkit.Foundation/Observable.cs @@ -2,11 +2,18 @@ namespace Toolkit.Foundation; -public partial class Observable : +public partial class Observable(IServiceProvider + provider, + IServiceFactory factory, + IMediator mediator, + IPublisher publisher, + ISubscriber subscriber, + IDisposer disposer) : ObservableObject, IObservableViewModel, IActivityIndicator, - IInitializer, + IPostInitialization, + IInitialization, IActivated, IDeactivating, IDeactivated, @@ -20,40 +27,25 @@ public partial class Observable : { private readonly Dictionary trackedProperties = []; - [ObservableProperty] - private bool initialized; - [ObservableProperty] private bool active; - public Observable(IServiceProvider - provider, - IServiceFactory factory, - IMediator mediator, - IPublisher publisher, - ISubscription subscriber, - IDisposer disposer) - { - Provider = provider; - Factory = factory; - Mediator = mediator; - Publisher = publisher; - Disposer = disposer; - - subscriber.Add(this); - } + [ObservableProperty] + private bool initialized; + private bool postInitialized; public event EventHandler? DeactivateHandler; - public IDisposer Disposer { get; } + public IDisposer Disposer { get; } = disposer; - public IServiceFactory Factory { get; } + public IServiceFactory Factory { get; } = factory; - public IMediator Mediator { get; } + public IMediator Mediator { get; } = mediator; - public IServiceProvider Provider { get; } + public IServiceProvider Provider { get; } = provider; - public IPublisher Publisher { get; } + public IPublisher Publisher { get; } = publisher; + public ISubscriber Subscriber { get; } = subscriber; public void Commit() { @@ -95,6 +87,17 @@ public partial class Observable : public virtual Task OnDeactivating() => Task.CompletedTask; + public virtual void PostInitialize() + { + if (postInitialized) + { + return; + } + + postInitialized = true; + Subscriber.Subscribe(this); + } + public void Revert() { foreach (object trackedProperty in trackedProperties.Values) @@ -124,7 +127,7 @@ public partial class Observable : IServiceFactory factory, IMediator mediator, IPublisher publisher, - ISubscription subscriber, + ISubscriber subscriber, IDisposer disposer, TValue value) : base(provider, factory, mediator, publisher, subscriber, disposer) { @@ -154,7 +157,7 @@ public partial class Observable : IServiceFactory factory, IMediator mediator, IPublisher publisher, - ISubscription subscriber, + ISubscriber subscriber, IDisposer disposer, TKey key, TValue value) : base(provider, factory, mediator, publisher, subscriber, disposer) diff --git a/Toolkit.Foundation/ObservableCollection.cs b/Toolkit.Foundation/ObservableCollection.cs index e67025a..73885bf 100644 --- a/Toolkit.Foundation/ObservableCollection.cs +++ b/Toolkit.Foundation/ObservableCollection.cs @@ -9,7 +9,8 @@ namespace Toolkit.Foundation; public partial class ObservableCollection : ObservableObject, IObservableCollectionViewModel, - IInitializer, + IPostInitialization, + IInitialization, IActivated, IDeactivating, IDeactivated, @@ -32,7 +33,7 @@ public partial class ObservableCollection : INotificationHandler>, INotificationHandler>, INotificationHandler> - where TItem : notnull, + where TItem : notnull, IDisposable { private readonly System.Collections.ObjectModel.ObservableCollection collection = []; @@ -52,6 +53,8 @@ public partial class ObservableCollection : [ObservableProperty] private bool initialized; + private bool postInitialized; + [ObservableProperty] private TItem? selectedItem; @@ -59,17 +62,16 @@ public partial class ObservableCollection : IServiceFactory factory, IMediator mediator, IPublisher publisher, - ISubscription subscriber, + ISubscriber subscriber, IDisposer disposer) { Provider = provider; Factory = factory; Mediator = mediator; Publisher = publisher; + Subscriber = subscriber; Disposer = disposer; - subscriber.Add(this); - dispatcher = Provider.GetRequiredService(); collection.CollectionChanged += OnCollectionChanged; } @@ -78,7 +80,7 @@ public partial class ObservableCollection : IServiceFactory factory, IMediator mediator, IPublisher publisher, - ISubscription subscriber, + ISubscriber subscriber, IDisposer disposer, IEnumerable items) { @@ -86,10 +88,9 @@ public partial class ObservableCollection : Factory = factory; Mediator = mediator; Publisher = publisher; + Subscriber = subscriber; Disposer = disposer; - subscriber.Add(this); - dispatcher = Provider.GetRequiredService(); collection.CollectionChanged += OnCollectionChanged; @@ -117,6 +118,7 @@ public partial class ObservableCollection : public IServiceProvider Provider { get; private set; } public IPublisher Publisher { get; private set; } + public ISubscriber Subscriber { get; } object ICollection.SyncRoot => this; @@ -149,18 +151,19 @@ public partial class ObservableCollection : where T : TItem { - T? item = Factory.Create(parameters); + T? item = Factory.Create(args => + { + if (args is IPostInitialization initialization) + { + initialization.PostInitialize(); + } + }, parameters); + Add(item); return item; } - public void Clear(Action> factory) - { - Clear(); - factory.Invoke(this); - } - public void Add(TItem item) { int index = collection.Count; @@ -200,6 +203,11 @@ public partial class ObservableCollection : } } + public void Clear(Action> factory) + { + Clear(); + factory.Invoke(this); + } public void Clear() { clearing = true; @@ -246,17 +254,6 @@ public partial class ObservableCollection : Disposer.Dispose(this); } - public void Fetch(bool reset = false) - { - if (reset) - { - Clear(); - } - - SynchronizeExpression expression = BuildAggregateExpression(); - Publisher.PublishUI(expression.Value, expression.Key); - } - public void Fetch(Func aggregateDelegate, bool reset = false) { @@ -268,6 +265,7 @@ public partial class ObservableCollection : SynchronizeExpression expression = aggregateDelegate.Invoke(); Publisher.PublishUI(expression.Value, expression.Key); } + public IEnumerator GetEnumerator() => collection.GetEnumerator(); @@ -413,7 +411,7 @@ public partial class ObservableCollection : } Initialized = true; - Fetch(); + Synchronize(); return Task.CompletedTask; } @@ -423,14 +421,21 @@ public partial class ObservableCollection : where T : TItem { - T? item = Factory.Create(parameters); + T? item = Factory.Create(args => + { + if (args is IPostInitialization initialization) + { + initialization.PostInitialize(); + } + }, parameters); + InsertItem(index, item); UpdateSelection(item); return item; } - public void Insert(int index, + public void Insert(int index, TItem item) { InsertItem(index, item); @@ -516,6 +521,17 @@ public partial class ObservableCollection : public virtual Task OnDeactivating() => Task.CompletedTask; + public virtual void PostInitialize() + { + if (postInitialized) + { + return; + } + + postInitialized = true; + Subscriber.Subscribe(this); + } + public bool Remove(TItem item) { int index = collection.IndexOf(item); @@ -574,6 +590,16 @@ public partial class ObservableCollection : } } + public void Synchronize(bool reset = false) + { + if (reset) + { + Clear(); + } + + SynchronizeExpression expression = BuildAggregateExpression(); + Publisher.PublishUI(expression.Value, expression.Key); + } public void Track(string propertyName, Func getter, Action setter) { if (!trackedProperties.ContainsKey(propertyName)) @@ -657,7 +683,7 @@ public partial class ObservableCollection(IServiceProvider p IServiceFactory factory, IMediator mediator, IPublisher publisher, - ISubscription subscriber, + ISubscriber subscriber, IDisposer disposer, TValue value) : ObservableCollection(provider, factory, mediator, publisher, subscriber, disposer) where TViewModel : notnull, IDisposable @@ -690,7 +716,7 @@ public partial class ObservableCollection : IServiceFactory factory, IMediator mediator, IPublisher publisher, - ISubscription subscriber, + ISubscriber subscriber, IDisposer disposer, TKey key, TValue value) : base(provider, factory, mediator, publisher, subscriber, disposer) @@ -703,7 +729,7 @@ public partial class ObservableCollection : IServiceFactory factory, IMediator mediator, IPublisher publisher, - ISubscription subscriber, + ISubscriber subscriber, IDisposer disposer, IEnumerable items, TKey key, @@ -728,7 +754,7 @@ public class ObservableCollection : IServiceFactory factory, IMediator mediator, IPublisher publisher, - ISubscription subscriber, + ISubscriber subscriber, IDisposer disposer) : base(provider, factory, mediator, publisher, subscriber, disposer) { } @@ -737,7 +763,7 @@ public class ObservableCollection : IServiceFactory factory, IMediator mediator, IPublisher publisher, - ISubscription subscriber, + ISubscriber subscriber, IDisposer disposer, IEnumerable items) : base(provider, factory, mediator, publisher, subscriber, disposer, items) { diff --git a/Toolkit.Foundation/ServiceFactory.cs b/Toolkit.Foundation/ServiceFactory.cs index 88cd537..74d4dfd 100644 --- a/Toolkit.Foundation/ServiceFactory.cs +++ b/Toolkit.Foundation/ServiceFactory.cs @@ -17,4 +17,13 @@ public class ServiceFactory(Func factory) : public object Create(Type type, params object?[]? parameters) => factory(type, parameters); + + public object Create(Type type, Action serviceDelegate, + params object?[]? parameters) + { + object service = factory(type, parameters); + serviceDelegate.Invoke(service); + + return service; + } } \ No newline at end of file diff --git a/Toolkit.Foundation/Subscription.cs b/Toolkit.Foundation/Subscriber.cs similarity index 96% rename from Toolkit.Foundation/Subscription.cs rename to Toolkit.Foundation/Subscriber.cs index f974bc2..0e6d04d 100644 --- a/Toolkit.Foundation/Subscription.cs +++ b/Toolkit.Foundation/Subscriber.cs @@ -2,11 +2,11 @@ namespace Toolkit.Foundation; -public class Subscription(SubscriptionCollection subscriptions, +public class Subscriber(SubscriptionCollection subscriptions, IDisposer disposer) : - ISubscription + ISubscriber { - public void Add(object subscriber) + public void Subscribe(object subscriber) { Type handlerType = subscriber.GetType(); @@ -45,7 +45,7 @@ public class Subscription(SubscriptionCollection subscriptions, } } - public void Remove(object subscriber) + public void Unsubscribe(object subscriber) { Type handlerType = subscriber.GetType(); IDictionary> subscribers = GetSubscriptionKeys(subscriber); diff --git a/Toolkit.Foundation/ValueViewModel.cs b/Toolkit.Foundation/ValueViewModel.cs index 4bfdb4f..3f39cfa 100644 --- a/Toolkit.Foundation/ValueViewModel.cs +++ b/Toolkit.Foundation/ValueViewModel.cs @@ -6,7 +6,7 @@ public partial class ValueViewModel(IServiceProvider provider, IServiceFactory factory, IMediator mediator, IPublisher publisher, - ISubscription subscriber, + ISubscriber subscriber, IDisposer disposer) : Observable(provider, factory, mediator, publisher, subscriber, disposer) {