Parameter improvements

This commit is contained in:
TheXamlGuy
2024-05-26 23:29:50 +01:00
parent baf504b815
commit cfc79e26f0
11 changed files with 136 additions and 115 deletions
+1 -6
View File
@@ -42,18 +42,13 @@ public class ContentTemplate :
async void HandleUnloaded(object? sender, RoutedEventArgs args) async void HandleUnloaded(object? sender, RoutedEventArgs args)
{ {
control.Unloaded -= HandleLoaded; control.Unloaded -= HandleUnloaded;
if (control.DataContext is object content) if (control.DataContext is object content)
{ {
if (content is IDeactivated deactivated) if (content is IDeactivated deactivated)
{ {
await deactivated.OnDeactivated(); await deactivated.OnDeactivated();
} }
//if (content is IDisposable disposable)
//{
// disposable.Dispose();
//}
} }
} }
+74 -32
View File
@@ -1,8 +1,9 @@
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Primitives; using Avalonia.Interactivity;
using FluentAvalonia.UI.Media.Animation; using FluentAvalonia.UI.Media.Animation;
using FluentAvalonia.UI.Navigation; using FluentAvalonia.UI.Navigation;
using Toolkit.Foundation; using Toolkit.Foundation;
using Toolkit.UI.Avalonia;
using Toolkit.UI.Controls.Avalonia; using Toolkit.UI.Controls.Avalonia;
namespace Toolkit.Avalonia; namespace Toolkit.Avalonia;
@@ -18,37 +19,19 @@ public class FrameHandler :
frame.NavigationPageFactory ??= new NavigationPageFactory(); frame.NavigationPageFactory ??= new NavigationPageFactory();
if (args.Template is Control control) if (args.Template is Control control)
{ {
void NavigatingFrom(Control sender) void NavigatedTo(Control sender)
{ {
async void HandleNavigatedTo(object? _,
NavigationEventArgs __)
{
sender.RemoveHandler(Frame.NavigatedToEvent, HandleNavigatedTo);
async void HandleNavigatingFrom(object? _, async void HandleNavigatingFrom(object? _,
NavigatingCancelEventArgs args) NavigatingCancelEventArgs args)
{ {
sender.RemoveHandler(Frame.NavigatingFromEvent, HandleNavigatingFrom); sender.RemoveHandler(Frame.NavigatingFromEvent, HandleNavigatingFrom);
NavigatedFrom(sender); control.Unloaded -= HandleUnloaded;
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? _, async void HandleNavigatedFrom(object? _,
NavigationEventArgs args) NavigationEventArgs args)
{ {
@@ -68,16 +51,25 @@ public class FrameHandler :
} }
sender.AddHandler(Frame.NavigatedFromEvent, HandleNavigatedFrom); sender.AddHandler(Frame.NavigatedFromEvent, HandleNavigatedFrom);
if (sender.DataContext is object content)
{
if (content is IConfirmation confirmation &&
!await confirmation.Confirm())
{
args.Cancel = true;
} }
void NavigatedTo(Control sender) if (!args.Cancel)
{ {
async void HandleNavigatedTo(object? _, if (content is IDeactivating deactivating)
NavigationEventArgs __)
{ {
sender.RemoveHandler(Frame.NavigatedToEvent, HandleNavigatedTo); await deactivating.OnDeactivating();
NavigatingFrom(sender); }
}
}
}
sender.AddHandler(Frame.NavigatingFromEvent, HandleNavigatingFrom);
if (sender.DataContext is object content) if (sender.DataContext is object content)
{ {
if (content is IInitializer initializer) if (content is IInitializer initializer)
@@ -90,6 +82,27 @@ public class FrameHandler :
await activated.OnActivated(); 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); sender.AddHandler(Frame.NavigatedToEvent, HandleNavigatedTo);
@@ -97,7 +110,30 @@ public class FrameHandler :
control.DataContext = args.Content; control.DataContext = args.Content;
NavigatedTo(control); 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<SlideNavigationTransitionEffect>($"{transition}")
};
break;
}
}
}
frame.NavigateFromObject(control, navigationOptions);
} }
} }
@@ -108,6 +144,12 @@ public class FrameHandler :
{ {
if (args.Context is Frame frame) if (args.Context is Frame frame)
{ {
//NavigationTransitionInfo? navigationTransitionInfo = null;
//if (frame.Content is IBackwardNavigation navigation)
//{
// navigationTransitionInfo = navigation.Transition;
//}
frame.GoBack(); frame.GoBack();
} }
+1 -1
View File
@@ -6,7 +6,7 @@ public interface INavigationScope
object? sender = null, object? sender = null,
object? region = null, object? region = null,
EventHandler? navigated = null, EventHandler? navigated = null,
object[]? parameters = null); IDictionary<string, object>? parameters = null);
void Back(object? region); void Back(object? region);
} }
+2 -1
View File
@@ -10,7 +10,8 @@ public class NavigateBackHandler(IComponentScopeProvider provider) :
if (provider.Get(args.Scope ?? "Root") if (provider.Get(args.Scope ?? "Root")
is ComponentScopeDescriptor descriptor) is ComponentScopeDescriptor descriptor)
{ {
if (descriptor?.Services?.GetService<INavigationScope>() is INavigationScope navigationScope) if (descriptor?.Services?.GetService<INavigationScope>() is
INavigationScope navigationScope)
{ {
navigationScope.Back(args.Context); navigationScope.Back(args.Context);
} }
+2 -2
View File
@@ -5,10 +5,10 @@ public record NavigateEventArgs(string Route,
string? Scope = null, string? Scope = null,
object? Sender = null, object? Sender = null,
EventHandler? Navigated = null, EventHandler? Navigated = null,
object[]? Parameters = null); IDictionary<string, object>? Parameters = null);
public record NavigateEventArgs<TNavigation>(object Region, public record NavigateEventArgs<TNavigation>(object Region,
object Template, object Template,
object Content, object Content,
object? Sender = null, object? Sender = null,
object[]? Parameters = null); IDictionary<string, object>? Parameters = null);
+14 -20
View File
@@ -14,7 +14,7 @@ public class NavigationScope(IPublisher publisher,
object? sender = null, object? sender = null,
object? region = null, object? region = null,
EventHandler? navigated = null, EventHandler? navigated = null,
object[]? parameters = null) IDictionary<string, object>? parameters = null)
{ {
if (region is null) if (region is null)
{ {
@@ -32,20 +32,14 @@ public class NavigationScope(IPublisher publisher,
if (contentTemplateDescriptorProvider.Get(segment) if (contentTemplateDescriptorProvider.Get(segment)
is IContentTemplateDescriptor descriptor) is IContentTemplateDescriptor descriptor)
{ {
Dictionary<string, object>? arguments = parameters?.OfType<KeyValuePair<string, object>>() Dictionary<string, object>? arguments = parameters?.ToDictionary(x => x.Key, x => x.Value, StringComparer.InvariantCultureIgnoreCase) ?? [];
.ToDictionary(x => x.Key, x => x.Value, StringComparer.InvariantCultureIgnoreCase) ?? []; object[]? resolvedArguments = parameters is not null ? [.. descriptor.ContentType
IEnumerable<object?>? mappedParameters = descriptor.ContentType
.GetConstructors() .GetConstructors()
.FirstOrDefault()? .FirstOrDefault()?
.GetParameters() .GetParameters()
.Select(parameter => parameter?.Name is not null && arguments .Select(x => x?.Name is not null && arguments
.TryGetValue(parameter.Name, out object? argument) ? argument : default) .TryGetValue(x.Name, out object? argument) ? argument : default)
.Where(argument => argument is not null); .Where(argument => argument is not null)] : [];
parameters = [.. parameters?.Where(x => x.GetType() != typeof(KeyValuePair<string, object>)) ??
Enumerable.Empty<object?>(),
.. mappedParameters ?? Enumerable.Empty<object?>()];
if (provider.GetRequiredKeyedService(descriptor.TemplateType, segment) is object view) if (provider.GetRequiredKeyedService(descriptor.TemplateType, segment) is object view)
{ {
@@ -69,8 +63,8 @@ public class NavigationScope(IPublisher publisher,
if (region is not null) if (region is not null)
{ {
if ((parameters is { Length: > 0 } if ((resolvedArguments is { Length: > 0 }
? factory.Create(descriptor.ContentType, parameters) ? factory.Create(descriptor.ContentType, resolvedArguments)
: provider.GetRequiredKeyedService(descriptor.ContentType, segment)) is object viewModel) : provider.GetRequiredKeyedService(descriptor.ContentType, segment)) is object viewModel)
{ {
if (navigationProvider.Get(region is Type type ? type : region.GetType()) is INavigation navigation) 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) is INavigation navigation)
{ {
Type navigateType = typeof(NavigateBackEventArgs<>).MakeGenericType(navigation.Type); 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); publisher.Publish(navigate);
} }
+8 -19
View File
@@ -2,6 +2,7 @@
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Metadata; using Avalonia.Metadata;
using Avalonia.Xaml.Interactivity; using Avalonia.Xaml.Interactivity;
using System.Collections.Immutable;
using Toolkit.Foundation; using Toolkit.Foundation;
namespace Toolkit.UI.Avalonia; namespace Toolkit.UI.Avalonia;
@@ -10,12 +11,9 @@ public class NavigateAction :
AvaloniaObject, AvaloniaObject,
IAction IAction
{ {
public static readonly DirectProperty<NavigateAction, ParameterBindingCollection> ParameterBindingsProperty = public static readonly DirectProperty<NavigateAction, ParameterCollection> ParametersProperty =
AvaloniaProperty.RegisterDirect<NavigateAction, ParameterBindingCollection>(nameof(ParameterBindings), AvaloniaProperty.RegisterDirect<NavigateAction, ParameterCollection>(nameof(Parameters),
x => x.ParameterBindings); x => x.Parameters);
public static readonly StyledProperty<object[]?> ParametersProperty =
AvaloniaProperty.Register<NavigateAction, object[]?>(nameof(Parameters));
public static readonly StyledProperty<object> RegionProperty = public static readonly StyledProperty<object> RegionProperty =
AvaloniaProperty.Register<NavigateAction, object>(nameof(Region)); AvaloniaProperty.Register<NavigateAction, object>(nameof(Region));
@@ -26,7 +24,7 @@ public class NavigateAction :
public static readonly StyledProperty<string> ScopeProperty = public static readonly StyledProperty<string> ScopeProperty =
AvaloniaProperty.Register<NavigateAction, string>(nameof(Scope)); AvaloniaProperty.Register<NavigateAction, string>(nameof(Scope));
private ParameterBindingCollection parameterCollection = []; private ParameterCollection parameterCollection = [];
public event EventHandler? Navigated; public event EventHandler? Navigated;
@@ -37,15 +35,9 @@ public class NavigateAction :
} }
[Content] [Content]
public ParameterBindingCollection ParameterBindings => public ParameterCollection Parameters =>
parameterCollection ??= []; parameterCollection ??= [];
public object[]? Parameters
{
get => GetValue(ParametersProperty);
set => SetValue(ParametersProperty, value);
}
public string Route public string Route
{ {
get => GetValue(RouteProperty); get => GetValue(RouteProperty);
@@ -68,11 +60,8 @@ public class NavigateAction :
if (content.DataContext is IObservableViewModel observableViewModel) if (content.DataContext is IObservableViewModel observableViewModel)
{ {
object[] parameters = [.. Parameters ?? Enumerable.Empty<object?>(), ImmutableDictionary<string, object>? parameters = Parameters is { Count: > 0 } ? Parameters.ToImmutableDictionary(x => x.Key, x => x.Value) :
.. ImmutableDictionary<string, object>.Empty;
ParameterBindings is { Count: > 0 } ?
ParameterBindings.Select(binding => new KeyValuePair<string, object>(binding.Key, binding.Value)).ToArray() :
Enumerable.Empty<KeyValuePair<string, object>>()];
observableViewModel.Publisher.Publish(new NavigateEventArgs(Route, Region == this ? content : Region, Scope ?? null, observableViewModel.Publisher.Publish(new NavigateEventArgs(Route, Region == this ? content : Region, Scope ?? null,
content.DataContext, Navigated, parameters)); content.DataContext, Navigated, parameters));
@@ -2,14 +2,14 @@
namespace Toolkit.UI.Avalonia; namespace Toolkit.UI.Avalonia;
public class ParameterBinding : public class Parameter :
AvaloniaObject AvaloniaObject
{ {
public static readonly StyledProperty<string> KeyProperty = public static readonly StyledProperty<string> KeyProperty =
AvaloniaProperty.Register<ParameterBinding, string>(nameof(Key)); AvaloniaProperty.Register<Parameter, string>(nameof(Key));
public static readonly StyledProperty<object> ValueProperty = public static readonly StyledProperty<object> ValueProperty =
AvaloniaProperty.Register<ParameterBinding, object>(nameof(Value)); AvaloniaProperty.Register<Parameter, object>(nameof(Value));
public string Key public string Key
{ {
@@ -1,6 +0,0 @@
using System.Collections.ObjectModel;
namespace Toolkit.UI.Avalonia;
public class ParameterBindingCollection :
ObservableCollection<ParameterBinding>;
@@ -0,0 +1,6 @@
using System.Collections.ObjectModel;
namespace Toolkit.UI.Avalonia;
public class ParameterCollection :
ObservableCollection<Parameter>;