From 7fa80371a4bb7d8404242c23652d2c619b2665ed Mon Sep 17 00:00:00 2001 From: TheXamlGuy Date: Mon, 22 Apr 2024 22:30:57 +0100 Subject: [PATCH] Add KeyBindingBehavior --- Toolkit.Foundation/ComponentInitializer.cs | 9 +++-- Toolkit.Foundation/ComponentScope.cs | 3 ++ .../ComponentScopeCollection.cs | 2 +- .../ComponentScopeDescriptor.cs | 3 ++ Toolkit.Foundation/ComponentScopeProvider.cs | 9 ++--- ...guration.cs => ConfigurationDescriptor.cs} | 4 +- .../ContentTemplateDescriptorProvider.cs | 4 +- Toolkit.Foundation/DefaultBuilder.cs | 5 ++- .../IComponentScopeCollection.cs | 2 +- Toolkit.Foundation/IComponentScopeProvider.cs | 2 +- ...uration.cs => IConfigurationDescriptor.cs} | 2 +- .../IServiceCollectionExtensions.cs | 10 ++--- Toolkit.Foundation/NavigateBackHandler.cs | 6 +-- Toolkit.Foundation/NavigateHandler.cs | 9 +++-- Toolkit.UI.Avalonia/ComparisonCondition.cs | 1 + Toolkit.UI.Avalonia/KeyBindingBehavior.cs | 38 +++++++++++++++++++ 16 files changed, 77 insertions(+), 32 deletions(-) create mode 100644 Toolkit.Foundation/ComponentScope.cs create mode 100644 Toolkit.Foundation/ComponentScopeDescriptor.cs rename Toolkit.Foundation/{Configuration.cs => ConfigurationDescriptor.cs} (65%) rename Toolkit.Foundation/{IConfiguration.cs => IConfigurationDescriptor.cs} (69%) create mode 100644 Toolkit.UI.Avalonia/KeyBindingBehavior.cs diff --git a/Toolkit.Foundation/ComponentInitializer.cs b/Toolkit.Foundation/ComponentInitializer.cs index a758541..be18151 100644 --- a/Toolkit.Foundation/ComponentInitializer.cs +++ b/Toolkit.Foundation/ComponentInitializer.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; namespace Toolkit.Foundation; @@ -35,12 +36,14 @@ public class ComponentInitializer(IEnumerable components, provider.GetRequiredService()); services.AddRange(typedServices.Services); + + services.AddSingleton(new ComponentScope(component.GetType().Name)); }); IComponentHost host = builder.Build(); - scopes.Add(component.GetType().Name, - host.Services.GetRequiredService()); + scopes.Add(new ComponentScopeDescriptor(component.GetType().Name, + provider.GetRequiredService())); hosts.Add(host); await host.StartAsync(); diff --git a/Toolkit.Foundation/ComponentScope.cs b/Toolkit.Foundation/ComponentScope.cs new file mode 100644 index 0000000..c403c54 --- /dev/null +++ b/Toolkit.Foundation/ComponentScope.cs @@ -0,0 +1,3 @@ +namespace Toolkit.Foundation; + +public record ComponentScope(string Name); diff --git a/Toolkit.Foundation/ComponentScopeCollection.cs b/Toolkit.Foundation/ComponentScopeCollection.cs index d944e5d..b9a42a7 100644 --- a/Toolkit.Foundation/ComponentScopeCollection.cs +++ b/Toolkit.Foundation/ComponentScopeCollection.cs @@ -1,4 +1,4 @@ namespace Toolkit.Foundation; -public class ComponentScopeCollection : Dictionary, +public class ComponentScopeCollection : List, IComponentScopeCollection; diff --git a/Toolkit.Foundation/ComponentScopeDescriptor.cs b/Toolkit.Foundation/ComponentScopeDescriptor.cs new file mode 100644 index 0000000..23380c7 --- /dev/null +++ b/Toolkit.Foundation/ComponentScopeDescriptor.cs @@ -0,0 +1,3 @@ +namespace Toolkit.Foundation; + +public record ComponentScopeDescriptor(string Key, IServiceProvider Services); \ No newline at end of file diff --git a/Toolkit.Foundation/ComponentScopeProvider.cs b/Toolkit.Foundation/ComponentScopeProvider.cs index f0b28f4..e29b8d4 100644 --- a/Toolkit.Foundation/ComponentScopeProvider.cs +++ b/Toolkit.Foundation/ComponentScopeProvider.cs @@ -3,10 +3,9 @@ public class ComponentScopeProvider(IComponentScopeCollection scopes) : IComponentScopeProvider { - public IServiceProvider? Get(string name) + public ComponentScopeDescriptor? Get(string key) { - return scopes.TryGetValue(name, - out IServiceProvider? scope) ? scope : default; + return scopes.FirstOrDefault(x => x.Key == key) is ComponentScopeDescriptor + descriptor ? descriptor : default; } -} - +} \ No newline at end of file diff --git a/Toolkit.Foundation/Configuration.cs b/Toolkit.Foundation/ConfigurationDescriptor.cs similarity index 65% rename from Toolkit.Foundation/Configuration.cs rename to Toolkit.Foundation/ConfigurationDescriptor.cs index fc9249d..347195c 100644 --- a/Toolkit.Foundation/Configuration.cs +++ b/Toolkit.Foundation/ConfigurationDescriptor.cs @@ -1,8 +1,8 @@ namespace Toolkit.Foundation; -public class Configuration(string section, +public class ConfigurationDescriptor(string section, IConfigurationReader reader) : - IConfiguration + IConfigurationDescriptor where TConfiguration : class { diff --git a/Toolkit.Foundation/ContentTemplateDescriptorProvider.cs b/Toolkit.Foundation/ContentTemplateDescriptorProvider.cs index a4f1404..fef28cb 100644 --- a/Toolkit.Foundation/ContentTemplateDescriptorProvider.cs +++ b/Toolkit.Foundation/ContentTemplateDescriptorProvider.cs @@ -1,6 +1,4 @@ -using System.Xml.Linq; - -namespace Toolkit.Foundation; +namespace Toolkit.Foundation; public class ContentTemplateDescriptorProvider(IEnumerable contentTemplates) : IContentTemplateDescriptorProvider diff --git a/Toolkit.Foundation/DefaultBuilder.cs b/Toolkit.Foundation/DefaultBuilder.cs index 92535f8..948e896 100644 --- a/Toolkit.Foundation/DefaultBuilder.cs +++ b/Toolkit.Foundation/DefaultBuilder.cs @@ -49,10 +49,11 @@ public class DefaultBuilder : services.AddTransient(); services.AddTransient(); - + + services.AddSingleton(new ComponentScope("Root")); services.AddScoped(provider => new ComponentScopeCollection { - { "Default", provider.GetRequiredService() } + new ComponentScopeDescriptor("Root", provider.GetRequiredService()) }); services.AddTransient(); diff --git a/Toolkit.Foundation/IComponentScopeCollection.cs b/Toolkit.Foundation/IComponentScopeCollection.cs index 72eb836..1dc26fa 100644 --- a/Toolkit.Foundation/IComponentScopeCollection.cs +++ b/Toolkit.Foundation/IComponentScopeCollection.cs @@ -1,5 +1,5 @@ namespace Toolkit.Foundation; public interface IComponentScopeCollection : - IDictionary; + IList; diff --git a/Toolkit.Foundation/IComponentScopeProvider.cs b/Toolkit.Foundation/IComponentScopeProvider.cs index bf5cfc2..220446e 100644 --- a/Toolkit.Foundation/IComponentScopeProvider.cs +++ b/Toolkit.Foundation/IComponentScopeProvider.cs @@ -2,6 +2,6 @@ public interface IComponentScopeProvider { - IServiceProvider? Get(string name); + ComponentScopeDescriptor? Get(string key); } diff --git a/Toolkit.Foundation/IConfiguration.cs b/Toolkit.Foundation/IConfigurationDescriptor.cs similarity index 69% rename from Toolkit.Foundation/IConfiguration.cs rename to Toolkit.Foundation/IConfigurationDescriptor.cs index 0af78a7..cad357a 100644 --- a/Toolkit.Foundation/IConfiguration.cs +++ b/Toolkit.Foundation/IConfigurationDescriptor.cs @@ -1,6 +1,6 @@ namespace Toolkit.Foundation; -public interface IConfiguration +public interface IConfigurationDescriptor where TConfiguration : class { diff --git a/Toolkit.Foundation/IServiceCollectionExtensions.cs b/Toolkit.Foundation/IServiceCollectionExtensions.cs index cba129e..e482ed6 100644 --- a/Toolkit.Foundation/IServiceCollectionExtensions.cs +++ b/Toolkit.Foundation/IServiceCollectionExtensions.cs @@ -3,9 +3,7 @@ using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.FileProviders.Physical; using Microsoft.Extensions.Hosting; -using System; using System.Text.Json; -using Toolkit.Foundation; namespace Toolkit.Foundation; @@ -145,11 +143,11 @@ public static class IServiceCollectionExtensions services.AddTransient, WritableConfiguration>(); - services.TryAddKeyedTransient>(section, (provider, key) => - new Configuration(section, provider.GetRequiredKeyedService>(key))); + services.TryAddKeyedTransient>(section, (provider, key) => + new ConfigurationDescriptor(section, provider.GetRequiredKeyedService>(key))); - services.AddTransient(provider => provider.GetRequiredKeyedService>(section)); - services.AddTransient(provider => provider.GetRequiredKeyedService>(section).Value); + services.AddTransient(provider => provider.GetRequiredKeyedService>(section)); + services.AddTransient(provider => provider.GetRequiredKeyedService>(section).Value); return services; } diff --git a/Toolkit.Foundation/NavigateBackHandler.cs b/Toolkit.Foundation/NavigateBackHandler.cs index d66c7e4..2efa23d 100644 --- a/Toolkit.Foundation/NavigateBackHandler.cs +++ b/Toolkit.Foundation/NavigateBackHandler.cs @@ -8,10 +8,10 @@ public class NavigateBackHandler(IComponentScopeProvider provider) : public async Task Handle(NavigateBack args, CancellationToken cancellationToken) { - if (provider.Get(args.Scope ?? "Default") - is IServiceProvider scope) + if (provider.Get(args.Scope ?? "Root") + is ComponentScopeDescriptor descriptor) { - if (scope.GetService() is INavigationScope navigationScope) + if (descriptor?.Services?.GetService() is INavigationScope navigationScope) { await navigationScope.NavigateBackAsync(args.Context, cancellationToken); } diff --git a/Toolkit.Foundation/NavigateHandler.cs b/Toolkit.Foundation/NavigateHandler.cs index a634319..e91cfd3 100644 --- a/Toolkit.Foundation/NavigateHandler.cs +++ b/Toolkit.Foundation/NavigateHandler.cs @@ -2,16 +2,17 @@ namespace Toolkit.Foundation; -public class NavigateHandler(IComponentScopeProvider provider) : +public class NavigateHandler(ComponentScope scope, + IComponentScopeProvider provider) : INotificationHandler { public async Task Handle(Navigate args, CancellationToken cancellationToken) { - if (provider.Get(args.Scope ?? "Default") - is IServiceProvider scope) + if (provider.Get(args.Scope ?? scope.Name) + is ComponentScopeDescriptor descriptor) { - if (scope.GetService() is INavigationScope navigationScope) + if (descriptor?.Services?.GetService() is INavigationScope navigationScope) { await navigationScope.NavigateAsync(args.Route, args.Sender, args.Context, args.Navigated, args.Parameters, cancellationToken); diff --git a/Toolkit.UI.Avalonia/ComparisonCondition.cs b/Toolkit.UI.Avalonia/ComparisonCondition.cs index 6d112be..bde4777 100644 --- a/Toolkit.UI.Avalonia/ComparisonCondition.cs +++ b/Toolkit.UI.Avalonia/ComparisonCondition.cs @@ -2,6 +2,7 @@ using Avalonia.Xaml.Interactivity; namespace Toolkit.UI.Avalonia; + public class ComparisonCondition : AvaloniaObject, ICondition diff --git a/Toolkit.UI.Avalonia/KeyBindingBehavior.cs b/Toolkit.UI.Avalonia/KeyBindingBehavior.cs new file mode 100644 index 0000000..20f2117 --- /dev/null +++ b/Toolkit.UI.Avalonia/KeyBindingBehavior.cs @@ -0,0 +1,38 @@ +using Avalonia; +using Avalonia.Input; +using Avalonia.Xaml.Interactivity; +using System.Windows.Input; + +namespace Toolkit.UI.Avalonia; + +public class KeyBindingBehavior : + Trigger, + ICommand +{ + public static readonly StyledProperty KeyBindingProperty = + AvaloniaProperty.Register(nameof(KeyBinding)); + + public KeyBinding KeyBinding + { + get => GetValue(KeyBindingProperty); + set => SetValue(KeyBindingProperty, value); + } + + public event EventHandler? CanExecuteChanged; + + protected override void OnAttached() + { + if (KeyBinding != null) + { + KeyBinding.Command = this; + AssociatedObject?.KeyBindings.Add(KeyBinding); + } + + base.OnAttached(); + } + + public bool CanExecute(object? parameter) => true; + + public void Execute(object? parameter) => + Interaction.ExecuteActions(AssociatedObject, Actions, null); +}