using Avalonia.Controls; using Avalonia.Controls.Primitives; using CommunityToolkit.Mvvm.Messaging; using FluentAvalonia.UI.Controls; namespace Toolkit.Foundation.Avalonia { public class NavigationRouter : INavigationRouter { private readonly INavigationRouteDescriptorCollection descriptors; private readonly IMessenger messenger; private readonly INamedDataTemplateFactory namedDataTemplateFactory; private readonly INamedTemplateFactory namedTemplateFactory; private readonly ITemplateDescriptorProvider templateDescriptorProvider; private readonly ITemplateFactory templateFactory; private readonly ITypedDataTemplateFactory typedDataTemplateFactory; public NavigationRouter(ITemplateDescriptorProvider templateDescriptorProvider, ITemplateFactory templateFactory, INamedTemplateFactory namedTemplateFactory, INamedDataTemplateFactory namedDataTemplateFactory, ITypedDataTemplateFactory typedDataTemplateFactory, IMessenger messenger, INavigationRouteDescriptorCollection descriptors) { this.templateDescriptorProvider = templateDescriptorProvider; this.templateFactory = templateFactory; this.namedTemplateFactory = namedTemplateFactory; this.namedDataTemplateFactory = namedDataTemplateFactory; this.typedDataTemplateFactory = typedDataTemplateFactory; this.messenger = messenger; this.descriptors = descriptors; } public Task InitializeAsync() { messenger.Register(this, (sender, args) => OnNavigate(args)); messenger.Register(this, (sender, args) => OnNavigateBack(args)); return Task.CompletedTask; } private async void OnNavigate(Navigate args) { object? data = null; object? template = null; Dictionary keyedParameters = new(); List parameters = new(); foreach (object? parameter in args.Parameters) { if (parameter is not null) { if (parameter is KeyValuePair keyed) { keyedParameters.Add(keyed.Key, keyed.Value); } else { parameters.Add(parameter); } } } if (args.Name is { Length: > 0 } name) { data = namedDataTemplateFactory.Create(name, parameters.ToArray()); template = namedTemplateFactory.Create(name); } if (args.Type is Type type) { data = typedDataTemplateFactory.Create(type, parameters.ToArray()); template = templateFactory.Create(data); } if (template is not null) { bool navigated = false; if (template is ContentDialog contentDialog) { navigated = await messenger.Send(new NavigationRouteRequest(contentDialog, data, template, keyedParameters)); } else { if (descriptors.FirstOrDefault(x => args.Route is string { } name && name == x.Name) is NavigationRouteDescriptor descriptor) { switch (descriptor.Route) { case Frame frame: navigated = await messenger.Send(new NavigationRouteRequest(frame, data, template, keyedParameters)); break; case ContentControl contentControl: navigated = await messenger.Send(new NavigationRouteRequest(contentControl, data, template, keyedParameters)); break; } } } if (navigated) { messenger.Send((Navigated)Navigated.Create((dynamic?)template, (dynamic?)data, keyedParameters)); } } else { if (descriptors.FirstOrDefault(x => args.Route is string { } name && name == x.Name) is NavigationRouteDescriptor descriptor) { if (descriptor.Route is ContentControl contentControl) { contentControl.Content = null; } } } } private void OnNavigateBack(NavigateBack args) { if (descriptors.FirstOrDefault(x => args.Route is string { } name && name == x.Name) is NavigationRouteDescriptor descriptor) { if (descriptor.Route is ContentControl { Content: TemplatedControl content }) { if (content.DataContext is IDisposable disposable) { disposable.Dispose(); } } if (descriptor.Route is Frame frame) { frame.GoBack(); } } } } }