From cfc79e26f0e34ec44a58d7babbdb04493fe699d1 Mon Sep 17 00:00:00 2001 From: TheXamlGuy Date: Sun, 26 May 2024 23:29:50 +0100 Subject: [PATCH] Parameter improvements --- Toolkit.Avalonia/ContentTemplate.cs | 7 +- Toolkit.Avalonia/FrameHandler.cs | 152 +++++++++++------- Toolkit.Foundation/INavigationScope.cs | 2 +- Toolkit.Foundation/NavigateBackHandler.cs | 3 +- Toolkit.Foundation/NavigateEventArgs.cs | 4 +- Toolkit.Foundation/NavigationScope.cs | 36 ++--- Toolkit.UI.Avalonia/ConditionCollection.cs | 2 +- Toolkit.UI.Avalonia/NavigateAction.cs | 27 +--- .../{ParameterBinding.cs => Parameter.cs} | 6 +- .../ParameterBindingCollection.cs | 6 - Toolkit.UI.Avalonia/ParameterCollection.cs | 6 + 11 files changed, 136 insertions(+), 115 deletions(-) rename Toolkit.UI.Avalonia/{ParameterBinding.cs => Parameter.cs} (71%) delete mode 100644 Toolkit.UI.Avalonia/ParameterBindingCollection.cs create mode 100644 Toolkit.UI.Avalonia/ParameterCollection.cs diff --git a/Toolkit.Avalonia/ContentTemplate.cs b/Toolkit.Avalonia/ContentTemplate.cs index 499fc8c..6e60b93 100644 --- a/Toolkit.Avalonia/ContentTemplate.cs +++ b/Toolkit.Avalonia/ContentTemplate.cs @@ -42,18 +42,13 @@ public class ContentTemplate : async void HandleUnloaded(object? sender, RoutedEventArgs args) { - control.Unloaded -= HandleLoaded; + control.Unloaded -= HandleUnloaded; if (control.DataContext is object content) { if (content is IDeactivated deactivated) { await deactivated.OnDeactivated(); } - - //if (content is IDisposable disposable) - //{ - // disposable.Dispose(); - //} } } diff --git a/Toolkit.Avalonia/FrameHandler.cs b/Toolkit.Avalonia/FrameHandler.cs index d435a5a..728c7cf 100644 --- a/Toolkit.Avalonia/FrameHandler.cs +++ b/Toolkit.Avalonia/FrameHandler.cs @@ -1,8 +1,9 @@ using Avalonia.Controls; -using Avalonia.Controls.Primitives; +using Avalonia.Interactivity; using FluentAvalonia.UI.Media.Animation; using FluentAvalonia.UI.Navigation; using Toolkit.Foundation; +using Toolkit.UI.Avalonia; using Toolkit.UI.Controls.Avalonia; namespace Toolkit.Avalonia; @@ -18,66 +19,57 @@ public class FrameHandler : frame.NavigationPageFactory ??= new NavigationPageFactory(); if (args.Template is Control control) { - void NavigatingFrom(Control sender) - { - async void HandleNavigatingFrom(object? _, - NavigatingCancelEventArgs args) - { - sender.RemoveHandler(Frame.NavigatingFromEvent, HandleNavigatingFrom); - NavigatedFrom(sender); - - if (sender.DataContext is object content) - { - if (content is IConfirmation confirmation && - !await confirmation.Confirm()) - { - args.Cancel = true; - } - - if (!args.Cancel) - { - if (content is IDeactivating deactivating) - { - await deactivating.OnDeactivating(); - } - } - } - } - - sender.AddHandler(Frame.NavigatingFromEvent, HandleNavigatingFrom); - } - - void NavigatedFrom(Control sender) - { - async void HandleNavigatedFrom(object? _, - NavigationEventArgs args) - { - sender.RemoveHandler(Frame.NavigatedFromEvent, HandleNavigatedFrom); - if (sender.DataContext is object content) - { - if (content is IDeactivated deactivated) - { - await deactivated.OnDeactivated(); - } - - if (content is IDisposable disposable) - { - disposable.Dispose(); - } - } - } - - sender.AddHandler(Frame.NavigatedFromEvent, HandleNavigatedFrom); - } - void NavigatedTo(Control sender) { async void HandleNavigatedTo(object? _, NavigationEventArgs __) { sender.RemoveHandler(Frame.NavigatedToEvent, HandleNavigatedTo); - NavigatingFrom(sender); + async void HandleNavigatingFrom(object? _, + NavigatingCancelEventArgs args) + { + sender.RemoveHandler(Frame.NavigatingFromEvent, HandleNavigatingFrom); + control.Unloaded -= HandleUnloaded; + + async void HandleNavigatedFrom(object? _, + NavigationEventArgs args) + { + sender.RemoveHandler(Frame.NavigatedFromEvent, HandleNavigatedFrom); + if (sender.DataContext is object content) + { + if (content is IDeactivated deactivated) + { + await deactivated.OnDeactivated(); + } + + if (content is IDisposable disposable) + { + disposable.Dispose(); + } + } + } + + sender.AddHandler(Frame.NavigatedFromEvent, HandleNavigatedFrom); + if (sender.DataContext is object content) + { + if (content is IConfirmation confirmation && + !await confirmation.Confirm()) + { + args.Cancel = true; + } + + if (!args.Cancel) + { + if (content is IDeactivating deactivating) + { + await deactivating.OnDeactivating(); + } + } + } + } + + sender.AddHandler(Frame.NavigatingFromEvent, HandleNavigatingFrom); if (sender.DataContext is object content) { if (content is IInitializer initializer) @@ -90,6 +82,27 @@ public class FrameHandler : await activated.OnActivated(); } } + + async void HandleUnloaded(object? _, RoutedEventArgs __) + { + sender.RemoveHandler(Frame.NavigatingFromEvent, HandleNavigatingFrom); + control.Unloaded -= HandleUnloaded; + + if (control.DataContext is object content) + { + if (content is IDeactivated deactivated) + { + await deactivated.OnDeactivated(); + } + + if (content is IDisposable disposable) + { + disposable.Dispose(); + } + } + } + + sender.Unloaded += HandleUnloaded; } sender.AddHandler(Frame.NavigatedToEvent, HandleNavigatedTo); @@ -97,7 +110,30 @@ public class FrameHandler : control.DataContext = args.Content; NavigatedTo(control); - frame.NavigateFromObject(control, new FrameNavigationOptions { TransitionInfoOverride = new SuppressNavigationTransitionInfo() }); + + FrameNavigationOptions navigationOptions = new(); + if (args.Parameters is not null) + { + if (args.Parameters.TryGetValue("Transition", out object? transition)) + { + switch($"{transition}") + { + case "FromLeft": + case "FromRight": + case "FromTop": + case "FromBottom": + navigationOptions.TransitionInfoOverride = + new SlideNavigationTransitionInfo + { + Effect = Enum.Parse($"{transition}") + }; + break; + } + } + } + + + frame.NavigateFromObject(control, navigationOptions); } } @@ -108,6 +144,12 @@ public class FrameHandler : { if (args.Context is Frame frame) { + //NavigationTransitionInfo? navigationTransitionInfo = null; + //if (frame.Content is IBackwardNavigation navigation) + //{ + // navigationTransitionInfo = navigation.Transition; + //} + frame.GoBack(); } diff --git a/Toolkit.Foundation/INavigationScope.cs b/Toolkit.Foundation/INavigationScope.cs index 2c8f519..d8b2755 100644 --- a/Toolkit.Foundation/INavigationScope.cs +++ b/Toolkit.Foundation/INavigationScope.cs @@ -6,7 +6,7 @@ public interface INavigationScope object? sender = null, object? region = null, EventHandler? navigated = null, - object[]? parameters = 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 fa0785f..fb56b64 100644 --- a/Toolkit.Foundation/NavigateBackHandler.cs +++ b/Toolkit.Foundation/NavigateBackHandler.cs @@ -10,7 +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 + INavigationScope navigationScope) { navigationScope.Back(args.Context); } diff --git a/Toolkit.Foundation/NavigateEventArgs.cs b/Toolkit.Foundation/NavigateEventArgs.cs index 432cd3e..62665f7 100644 --- a/Toolkit.Foundation/NavigateEventArgs.cs +++ b/Toolkit.Foundation/NavigateEventArgs.cs @@ -5,10 +5,10 @@ public record NavigateEventArgs(string Route, string? Scope = null, object? Sender = null, EventHandler? Navigated = null, - object[]? Parameters = null); + IDictionary? Parameters = null); public record NavigateEventArgs(object Region, object Template, object Content, object? Sender = null, - object[]? Parameters = null); \ No newline at end of file + IDictionary? Parameters = null); \ No newline at end of file diff --git a/Toolkit.Foundation/NavigationScope.cs b/Toolkit.Foundation/NavigationScope.cs index a763cd4..a7e01dc 100644 --- a/Toolkit.Foundation/NavigationScope.cs +++ b/Toolkit.Foundation/NavigationScope.cs @@ -14,7 +14,7 @@ public class NavigationScope(IPublisher publisher, object? sender = null, object? region = null, EventHandler? navigated = null, - object[]? parameters = null) + IDictionary? parameters = null) { if (region is null) { @@ -32,20 +32,14 @@ public class NavigationScope(IPublisher publisher, if (contentTemplateDescriptorProvider.Get(segment) is IContentTemplateDescriptor descriptor) { - Dictionary? arguments = parameters?.OfType>() - .ToDictionary(x => x.Key, x => x.Value, StringComparer.InvariantCultureIgnoreCase) ?? []; - - IEnumerable? mappedParameters = descriptor.ContentType + Dictionary? arguments = parameters?.ToDictionary(x => x.Key, x => x.Value, StringComparer.InvariantCultureIgnoreCase) ?? []; + object[]? resolvedArguments = parameters is not null ? [.. descriptor.ContentType .GetConstructors() .FirstOrDefault()? .GetParameters() - .Select(parameter => parameter?.Name is not null && arguments - .TryGetValue(parameter.Name, out object? argument) ? argument : default) - .Where(argument => argument is not null); - - parameters = [.. parameters?.Where(x => x.GetType() != typeof(KeyValuePair)) ?? - Enumerable.Empty(), - .. mappedParameters ?? Enumerable.Empty()]; + .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, segment) is object view) { @@ -69,9 +63,9 @@ public class NavigationScope(IPublisher publisher, if (region is not null) { - if ((parameters is { Length: > 0 } - ? factory.Create(descriptor.ContentType, parameters) - : provider.GetRequiredKeyedService(descriptor.ContentType, segment)) is object viewModel) + if ((resolvedArguments is { Length: > 0 } + ? factory.Create(descriptor.ContentType, resolvedArguments) + : provider.GetRequiredKeyedService(descriptor.ContentType, segment)) is object viewModel) { if (navigationProvider.Get(region is Type type ? type : region.GetType()) is INavigation navigation) { @@ -92,20 +86,20 @@ public class NavigationScope(IPublisher publisher, } } - public void Back(object? context) + public void Back(object? region) { - if (context is not null) + if (region is not null) { - navigationRegionProvider.TryGet(context, out context); + navigationRegionProvider.TryGet(region, out region); } - if (context is not null) + if (region is not null) { - if (navigationProvider.Get(context is Type type ? type : context.GetType()) + if (navigationProvider.Get(region is Type type ? type : region.GetType()) is INavigation navigation) { Type navigateType = typeof(NavigateBackEventArgs<>).MakeGenericType(navigation.Type); - if (Activator.CreateInstance(navigateType, [context]) is object navigate) + if (Activator.CreateInstance(navigateType, [region]) is object navigate) { publisher.Publish(navigate); } diff --git a/Toolkit.UI.Avalonia/ConditionCollection.cs b/Toolkit.UI.Avalonia/ConditionCollection.cs index d8bee8c..36f0c69 100644 --- a/Toolkit.UI.Avalonia/ConditionCollection.cs +++ b/Toolkit.UI.Avalonia/ConditionCollection.cs @@ -5,4 +5,4 @@ namespace Toolkit.UI.Avalonia; public class ConditionCollection : ObservableCollection { -} \ No newline at end of file +} diff --git a/Toolkit.UI.Avalonia/NavigateAction.cs b/Toolkit.UI.Avalonia/NavigateAction.cs index 017632e..cd9f277 100644 --- a/Toolkit.UI.Avalonia/NavigateAction.cs +++ b/Toolkit.UI.Avalonia/NavigateAction.cs @@ -2,6 +2,7 @@ using Avalonia.Controls; using Avalonia.Metadata; using Avalonia.Xaml.Interactivity; +using System.Collections.Immutable; using Toolkit.Foundation; namespace Toolkit.UI.Avalonia; @@ -10,12 +11,9 @@ public class NavigateAction : AvaloniaObject, IAction { - public static readonly DirectProperty ParameterBindingsProperty = - AvaloniaProperty.RegisterDirect(nameof(ParameterBindings), - x => x.ParameterBindings); - - public static readonly StyledProperty ParametersProperty = - AvaloniaProperty.Register(nameof(Parameters)); + public static readonly DirectProperty ParametersProperty = + AvaloniaProperty.RegisterDirect(nameof(Parameters), + x => x.Parameters); public static readonly StyledProperty RegionProperty = AvaloniaProperty.Register(nameof(Region)); @@ -26,7 +24,7 @@ public class NavigateAction : public static readonly StyledProperty ScopeProperty = AvaloniaProperty.Register(nameof(Scope)); - private ParameterBindingCollection parameterCollection = []; + private ParameterCollection parameterCollection = []; public event EventHandler? Navigated; @@ -37,15 +35,9 @@ public class NavigateAction : } [Content] - public ParameterBindingCollection ParameterBindings => + public ParameterCollection Parameters => parameterCollection ??= []; - public object[]? Parameters - { - get => GetValue(ParametersProperty); - set => SetValue(ParametersProperty, value); - } - public string Route { get => GetValue(RouteProperty); @@ -68,11 +60,8 @@ public class NavigateAction : if (content.DataContext is IObservableViewModel observableViewModel) { - object[] parameters = [.. Parameters ?? Enumerable.Empty(), - .. - ParameterBindings is { Count: > 0 } ? - ParameterBindings.Select(binding => new KeyValuePair(binding.Key, binding.Value)).ToArray() : - Enumerable.Empty>()]; + ImmutableDictionary? parameters = Parameters is { Count: > 0 } ? Parameters.ToImmutableDictionary(x => x.Key, x => x.Value) : + ImmutableDictionary.Empty; observableViewModel.Publisher.Publish(new NavigateEventArgs(Route, Region == this ? content : Region, Scope ?? null, content.DataContext, Navigated, parameters)); diff --git a/Toolkit.UI.Avalonia/ParameterBinding.cs b/Toolkit.UI.Avalonia/Parameter.cs similarity index 71% rename from Toolkit.UI.Avalonia/ParameterBinding.cs rename to Toolkit.UI.Avalonia/Parameter.cs index 16ec964..e6c4629 100644 --- a/Toolkit.UI.Avalonia/ParameterBinding.cs +++ b/Toolkit.UI.Avalonia/Parameter.cs @@ -2,14 +2,14 @@ namespace Toolkit.UI.Avalonia; -public class ParameterBinding : +public class Parameter : AvaloniaObject { public static readonly StyledProperty KeyProperty = - AvaloniaProperty.Register(nameof(Key)); + AvaloniaProperty.Register(nameof(Key)); public static readonly StyledProperty ValueProperty = - AvaloniaProperty.Register(nameof(Value)); + AvaloniaProperty.Register(nameof(Value)); public string Key { diff --git a/Toolkit.UI.Avalonia/ParameterBindingCollection.cs b/Toolkit.UI.Avalonia/ParameterBindingCollection.cs deleted file mode 100644 index 734b597..0000000 --- a/Toolkit.UI.Avalonia/ParameterBindingCollection.cs +++ /dev/null @@ -1,6 +0,0 @@ -using System.Collections.ObjectModel; - -namespace Toolkit.UI.Avalonia; - -public class ParameterBindingCollection : - ObservableCollection; \ No newline at end of file diff --git a/Toolkit.UI.Avalonia/ParameterCollection.cs b/Toolkit.UI.Avalonia/ParameterCollection.cs new file mode 100644 index 0000000..ebc4d99 --- /dev/null +++ b/Toolkit.UI.Avalonia/ParameterCollection.cs @@ -0,0 +1,6 @@ +using System.Collections.ObjectModel; + +namespace Toolkit.UI.Avalonia; + +public class ParameterCollection : + ObservableCollection; \ No newline at end of file