From 56a9d5b075a7aa6052b3fa0fe32833b58b498d51 Mon Sep 17 00:00:00 2001 From: Allan Ritchie Date: Thu, 30 May 2024 23:30:37 -0400 Subject: [PATCH] We now have some tabs & nav stacks picking up properly --- Sample/AnotherPage.xaml | 13 ++++ Sample/AnotherPage.xaml.cs | 15 +++++ Sample/AnotherViewModel.cs | 8 +++ Sample/BlazorPage.xaml | 8 +++ Sample/BlazorViewModel.cs | 5 +- Sample/EventViewModel.cs | 5 +- Sample/MauiProgram.cs | 1 + Sample/Sample.csproj | 1 + readme.md | 6 +- src/Shiny.Mediator.Maui/MauiEventCollector.cs | 67 +++++++++++++------ src/Shiny.Mediator/Impl/Mediator.cs | 16 ++++- 11 files changed, 113 insertions(+), 32 deletions(-) create mode 100644 Sample/AnotherPage.xaml create mode 100644 Sample/AnotherPage.xaml.cs create mode 100644 Sample/AnotherViewModel.cs diff --git a/Sample/AnotherPage.xaml b/Sample/AnotherPage.xaml new file mode 100644 index 0000000..c5b25e0 --- /dev/null +++ b/Sample/AnotherPage.xaml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/Sample/AnotherPage.xaml.cs b/Sample/AnotherPage.xaml.cs new file mode 100644 index 0000000..e91d9fc --- /dev/null +++ b/Sample/AnotherPage.xaml.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sample; + +public partial class AnotherPage : ContentPage +{ + public AnotherPage() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/Sample/AnotherViewModel.cs b/Sample/AnotherViewModel.cs new file mode 100644 index 0000000..240fbf1 --- /dev/null +++ b/Sample/AnotherViewModel.cs @@ -0,0 +1,8 @@ +namespace Sample; + + +public class AnotherViewModel(BaseServices services, AppSqliteConnection conn) : ViewModel(services), IEventHandler +{ + public Task Handle(MyMessageEvent @event, CancellationToken cancellationToken) => + conn.Log("AnotherViewModel", @event); +} \ No newline at end of file diff --git a/Sample/BlazorPage.xaml b/Sample/BlazorPage.xaml index dcf3dd3..f907ee0 100644 --- a/Sample/BlazorPage.xaml +++ b/Sample/BlazorPage.xaml @@ -2,8 +2,16 @@ + + + + diff --git a/Sample/BlazorViewModel.cs b/Sample/BlazorViewModel.cs index 8da26e7..44c0c8c 100644 --- a/Sample/BlazorViewModel.cs +++ b/Sample/BlazorViewModel.cs @@ -1,8 +1,5 @@ namespace Sample; -public class BlazorViewModel : ViewModel +public class BlazorViewModel(BaseServices services) : ViewModel(services) { - public BlazorViewModel(BaseServices services) : base(services) - { - } } \ No newline at end of file diff --git a/Sample/EventViewModel.cs b/Sample/EventViewModel.cs index 92dbdd3..de15ccb 100644 --- a/Sample/EventViewModel.cs +++ b/Sample/EventViewModel.cs @@ -1,5 +1,3 @@ - - namespace Sample; @@ -19,7 +17,7 @@ AppSqliteConnection conn x.Arg, x.FireAndForget, x.ParallelEvents, - x.Timestamp.ToString("g") + x.Timestamp.ToLocalTime().ToString("g") )) .ToList(); }); @@ -40,7 +38,6 @@ AppSqliteConnection conn public ICommand Load { get; } [Reactive] public List List { get; private set; } - public override void OnAppearing() { base.OnAppearing(); diff --git a/Sample/MauiProgram.cs b/Sample/MauiProgram.cs index 59e4e4b..0082550 100644 --- a/Sample/MauiProgram.cs +++ b/Sample/MauiProgram.cs @@ -50,6 +50,7 @@ public static MauiApp CreateMauiApp() builder.Services.RegisterForNavigation(); builder.Services.RegisterForNavigation(); builder.Services.RegisterForNavigation(); + builder.Services.RegisterForNavigation(); return builder.Build(); } diff --git a/Sample/Sample.csproj b/Sample/Sample.csproj index 01689d7..42c3731 100644 --- a/Sample/Sample.csproj +++ b/Sample/Sample.csproj @@ -100,6 +100,7 @@ + diff --git a/readme.md b/readme.md index e8638eb..703326a 100644 --- a/readme.md +++ b/readme.md @@ -15,6 +15,10 @@ and dependency injection can't reach. * Fire & Forget as well as Parallel Event execution * Our MAUI & Blazor integrations allow your viewmodels or pages to implement an IEventHandler interface(s) without them having to participate in the dependency injection provider * We still have a "messagingcenter" type subscribe off IMediator for cases where you can't have your current type implement an interface +* Instead of Assembly Scanning, we have source generators to automatically wireup the necessary registrations for you! +* Lightweight, No external dependencies, tiny bit of reflection +* Help remove service overrun and reduce your constructor fat +* Easy to Unit Test ## Works With * .NET MAUI - all platforms @@ -159,6 +163,6 @@ Focus on the interfaces from the mediator & the mediator calls itself * Pipelines * Error handlers - requests and events? * Pre/Post Execution - Time how long events took, time how long a command took - * Explain Event Handlers * Streams - IAsyncEnumerable or IObservable +* Source Generator Registration diff --git a/src/Shiny.Mediator.Maui/MauiEventCollector.cs b/src/Shiny.Mediator.Maui/MauiEventCollector.cs index 277de11..5adcb22 100644 --- a/src/Shiny.Mediator.Maui/MauiEventCollector.cs +++ b/src/Shiny.Mediator.Maui/MauiEventCollector.cs @@ -4,31 +4,58 @@ public class MauiEventCollector : IEventCollector { public IReadOnlyList> GetHandlers() where TEvent : IEvent { + // I need to make this crawl the tree, but really I don't need a ton of use-cases here var list = new List>(); - var proxy = Application.Current?.NavigationProxy; - if (proxy != null) + var mainPage = Application.Current?.MainPage; + if (mainPage == null) + return list; + + if (mainPage is TabbedPage tabs) { - foreach (var page in proxy.NavigationStack) + foreach (var tab in tabs.Children) { - // if (page is TabbedPage tabs) - // { - // foreach (var tab in tabs.Children) - // { - // tab.NavigationProxy - // } - // } - // if (page is NavigationPage nav) - // { - // nav.NavigationProxy - // } - - if (page is IEventHandler handler1) - list.Add(handler1); - - if (page.BindingContext is IEventHandler handler2) - list.Add(handler2); + if (tab is NavigationPage navPage) + { + TryAppendEvents(navPage, list); + } + else + { + TryAppendEvents(tab, list); + } } } + else if (mainPage is NavigationPage navPage) + { + TryAppendEvents(navPage, list); + } + else + { + TryAppendEvents(mainPage!, list); + } + return list; } + + + static void TryAppendEvents(Page page, List> list) where TEvent : IEvent + { + if (page is IEventHandler handler1) + list.Add(handler1); + + if (page.BindingContext is IEventHandler handler2) + list.Add(handler2); + } + + + static void TryAppendEvents(NavigationPage navPage, List> list) where TEvent : IEvent + { + var navStack = navPage.Navigation?.NavigationStack; + if (navStack != null) + { + foreach (var page in navStack) + { + TryAppendEvents(page, list); + } + } + } } \ No newline at end of file diff --git a/src/Shiny.Mediator/Impl/Mediator.cs b/src/Shiny.Mediator/Impl/Mediator.cs index babda65..9a09bb2 100644 --- a/src/Shiny.Mediator/Impl/Mediator.cs +++ b/src/Shiny.Mediator/Impl/Mediator.cs @@ -19,7 +19,10 @@ public async Task Send(TRequest request, CancellationToken cancellatio AssertRequestHandlers(handlers.Count, request); // TODO: pipelines - await handlers.First().Handle(request, cancellationToken).ConfigureAwait(false); + await handlers + .First() + .Handle(request, cancellationToken) + .ConfigureAwait(false); } @@ -46,11 +49,12 @@ public async Task Publish( CancellationToken cancellationToken = default ) where TEvent : IEvent { + // TODO: filter out the dupes from the collector by instance (viewmodels may be in DI and MAUI collector) var handlers = services.GetServices>().ToList(); AppendHandlersIf(handlers, this.subscriptions); if (collector != null) AppendHandlersIf(handlers, collector); - + if (handlers.Count == 0) return; @@ -114,7 +118,13 @@ static void AppendHandlersIf(List> list, IEventCol { var handlers = collector.GetHandlers(); if (handlers.Count > 0) - list.AddRange(handlers); + { + foreach (var handler in handlers) + { + if (!list.Contains(handler)) + list.Add(handler); + } + } }