From 3ec77c8e37dcf409982cdc5fe799c99704f4abd9 Mon Sep 17 00:00:00 2001 From: dartasen Date: Mon, 16 Feb 2026 11:49:40 +0100 Subject: [PATCH 1/5] Add support for NavigatingFromEventArgs --- .../NavigatingFromEventArgsExtensionsTests.cs | 78 +++++++++++++++++++ ...avigatingFromEventArgsExtensions.shared.cs | 16 ++++ 2 files changed, 94 insertions(+) create mode 100644 src/CommunityToolkit.Maui.UnitTests/Extensions/NavigatingFromEventArgsExtensionsTests.cs create mode 100644 src/CommunityToolkit.Maui/Extensions/NavigatingFromEventArgsExtensions.shared.cs diff --git a/src/CommunityToolkit.Maui.UnitTests/Extensions/NavigatingFromEventArgsExtensionsTests.cs b/src/CommunityToolkit.Maui.UnitTests/Extensions/NavigatingFromEventArgsExtensionsTests.cs new file mode 100644 index 0000000000..ca25656cc6 --- /dev/null +++ b/src/CommunityToolkit.Maui.UnitTests/Extensions/NavigatingFromEventArgsExtensionsTests.cs @@ -0,0 +1,78 @@ +using CommunityToolkit.Maui.Extensions; +using CommunityToolkit.Maui.UnitTests.Mocks; +using Xunit; + +namespace CommunityToolkit.Maui.UnitTests.Extensions; + +public class NavigatingFromEventArgsExtensionsTests : BaseViewTest +{ + [Fact] + public async Task NavigatingFromEventArgsExtensions_IsDestinationPageACommunityToolkitPopupPage_ShouldReturnTrue() + { + // Arrange + MockApplication application = (MockApplication)ServiceProvider.GetRequiredService(); + IPopupService popupService = ServiceProvider.GetRequiredService(); + + Shell shell = (Shell)(application.Windows[0].Page ?? throw new InvalidOperationException("Unable to retrieve Shell")); + Page mainPage = shell.CurrentPage; + ShellContentPage shellContentPage = new(); + + Dictionary shellParameters = new() + { + { nameof(ContentPage.BackgroundColor), Colors.Orange } + }; + + TaskCompletionSource isDestinationPageACommunityToolkitPopupPageTCS = new(); + shellContentPage.NavigatingFromEventArgsReceived += (sender, args) => + { + isDestinationPageACommunityToolkitPopupPageTCS.SetResult(args.IsDestinationPageACommunityToolkitPopupPage()); + }; + + // Act + await mainPage.Navigation.PushAsync(shellContentPage); + await popupService.ShowPopupAsync(shell, null, shellParameters, TestContext.Current.CancellationToken); + bool? isDestinationPageACommunityToolkitPopupPage = await isDestinationPageACommunityToolkitPopupPageTCS.Task; + + // Assert + Assert.True(isDestinationPageACommunityToolkitPopupPage); + } + + [Fact] + public async Task NavigatingFromEventArgsExtensions_IsDestinationPageACommunityToolkitPopupPage_ShouldReturnFalse() + { + // Arrange + MockApplication application = (MockApplication)ServiceProvider.GetRequiredService(); + IPopupService popupService = ServiceProvider.GetRequiredService(); + + Shell shell = (Shell)(application.Windows[0].Page ?? throw new InvalidOperationException("Unable to retrieve Shell")); + Page mainPage = shell.CurrentPage; + + ShellContentPage shellContentPage = new(); + ShellContentPage anotherShellContentPage = new(); + + TaskCompletionSource isDestinationPageACommunityToolkitPopupPageTCS = new(); + shellContentPage.NavigatingFromEventArgsReceived += (sender, args) => + { + isDestinationPageACommunityToolkitPopupPageTCS.SetResult(args.IsDestinationPageACommunityToolkitPopupPage()); + }; + + // Act + await mainPage.Navigation.PushAsync(shellContentPage); + await mainPage.Navigation.PushAsync(anotherShellContentPage); + bool? isDestinationPageACommunityToolkitPopupPage = await isDestinationPageACommunityToolkitPopupPageTCS.Task; + + // Assert + Assert.False(isDestinationPageACommunityToolkitPopupPage); + } + + sealed class ShellContentPage : ContentPage + { + public event EventHandler? NavigatingFromEventArgsReceived; + + protected override void OnNavigatingFrom(NavigatingFromEventArgs args) + { + base.OnNavigatingFrom(args); + NavigatingFromEventArgsReceived?.Invoke(this, args); + } + } +} \ No newline at end of file diff --git a/src/CommunityToolkit.Maui/Extensions/NavigatingFromEventArgsExtensions.shared.cs b/src/CommunityToolkit.Maui/Extensions/NavigatingFromEventArgsExtensions.shared.cs new file mode 100644 index 0000000000..1563efbf81 --- /dev/null +++ b/src/CommunityToolkit.Maui/Extensions/NavigatingFromEventArgsExtensions.shared.cs @@ -0,0 +1,16 @@ +using CommunityToolkit.Maui.Views; + +namespace CommunityToolkit.Maui.Extensions; + +/// +/// Extension methods for . +/// +public static class NavigatingFromEventArgsExtensions +{ + /// + /// Determines if the destination page will be a Community Toolkit . + /// + /// The current . + /// A boolean indicating if the destination page will be a Community Toolkit . + public static bool IsDestinationPageACommunityToolkitPopupPage(this NavigatingFromEventArgs args) => args.DestinationPage is PopupPage; +} From 0a4dd089584c21b854a65210eb8e1f84407d4a27 Mon Sep 17 00:00:00 2001 From: dartasen Date: Mon, 16 Feb 2026 11:50:22 +0100 Subject: [PATCH 2/5] Adjust documentation of NavigatedFromEventArgsExtensions --- .../Extensions/NavigatedFromEventArgsExtensions.shared.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CommunityToolkit.Maui/Extensions/NavigatedFromEventArgsExtensions.shared.cs b/src/CommunityToolkit.Maui/Extensions/NavigatedFromEventArgsExtensions.shared.cs index 174cadc492..931c70bc39 100644 --- a/src/CommunityToolkit.Maui/Extensions/NavigatedFromEventArgsExtensions.shared.cs +++ b/src/CommunityToolkit.Maui/Extensions/NavigatedFromEventArgsExtensions.shared.cs @@ -8,9 +8,9 @@ namespace CommunityToolkit.Maui.Extensions; public static class NavigatedFromEventArgsExtensions { /// - /// Determines whether the previous page was a Community Toolkit . + /// Determines if the destination page is a Community Toolkit . /// /// The current . - /// A boolean indicating whether the previous page was a Community Toolkit . + /// A boolean indicating if the destination page is a Community Toolkit . public static bool IsDestinationPageACommunityToolkitPopupPage(this NavigatedFromEventArgs args) => args.DestinationPage is PopupPage; } \ No newline at end of file From 484f7164b4048521f3f7ec76e0a888088c09b466 Mon Sep 17 00:00:00 2001 From: Brandon Minnick <13558917+TheCodeTraveler@users.noreply.github.com> Date: Wed, 18 Feb 2026 10:17:36 -0800 Subject: [PATCH 3/5] Consolidate NavigationEventArgsExtensions --- ...NavigatedFromEventArgsExtensions.shared.cs | 16 ---------- .../NavigatedToEventArgsExtensions.shared.cs | 16 ---------- ...avigatingFromEventArgsExtensions.shared.cs | 16 ---------- .../NavigationEventArgsExtensions.cs | 30 +++++++++++++++++++ 4 files changed, 30 insertions(+), 48 deletions(-) delete mode 100644 src/CommunityToolkit.Maui/Extensions/NavigatedFromEventArgsExtensions.shared.cs delete mode 100644 src/CommunityToolkit.Maui/Extensions/NavigatedToEventArgsExtensions.shared.cs delete mode 100644 src/CommunityToolkit.Maui/Extensions/NavigatingFromEventArgsExtensions.shared.cs create mode 100644 src/CommunityToolkit.Maui/Extensions/NavigationEventArgsExtensions.cs diff --git a/src/CommunityToolkit.Maui/Extensions/NavigatedFromEventArgsExtensions.shared.cs b/src/CommunityToolkit.Maui/Extensions/NavigatedFromEventArgsExtensions.shared.cs deleted file mode 100644 index 931c70bc39..0000000000 --- a/src/CommunityToolkit.Maui/Extensions/NavigatedFromEventArgsExtensions.shared.cs +++ /dev/null @@ -1,16 +0,0 @@ -using CommunityToolkit.Maui.Views; - -namespace CommunityToolkit.Maui.Extensions; - -/// -/// Extension methods for . -/// -public static class NavigatedFromEventArgsExtensions -{ - /// - /// Determines if the destination page is a Community Toolkit . - /// - /// The current . - /// A boolean indicating if the destination page is a Community Toolkit . - public static bool IsDestinationPageACommunityToolkitPopupPage(this NavigatedFromEventArgs args) => args.DestinationPage is PopupPage; -} \ No newline at end of file diff --git a/src/CommunityToolkit.Maui/Extensions/NavigatedToEventArgsExtensions.shared.cs b/src/CommunityToolkit.Maui/Extensions/NavigatedToEventArgsExtensions.shared.cs deleted file mode 100644 index 961bed55a2..0000000000 --- a/src/CommunityToolkit.Maui/Extensions/NavigatedToEventArgsExtensions.shared.cs +++ /dev/null @@ -1,16 +0,0 @@ -using CommunityToolkit.Maui.Views; - -namespace CommunityToolkit.Maui.Extensions; - -/// -/// Extension methods for . -/// -public static class NavigatedToEventArgsExtensions -{ - /// - /// Determines whether the previous page was a Community Toolkit . - /// - /// The current . - /// A boolean indicating whether the previous page was a Community Toolkit . - public static bool WasPreviousPageACommunityToolkitPopupPage(this NavigatedToEventArgs args) => args.PreviousPage is PopupPage; -} \ No newline at end of file diff --git a/src/CommunityToolkit.Maui/Extensions/NavigatingFromEventArgsExtensions.shared.cs b/src/CommunityToolkit.Maui/Extensions/NavigatingFromEventArgsExtensions.shared.cs deleted file mode 100644 index 1563efbf81..0000000000 --- a/src/CommunityToolkit.Maui/Extensions/NavigatingFromEventArgsExtensions.shared.cs +++ /dev/null @@ -1,16 +0,0 @@ -using CommunityToolkit.Maui.Views; - -namespace CommunityToolkit.Maui.Extensions; - -/// -/// Extension methods for . -/// -public static class NavigatingFromEventArgsExtensions -{ - /// - /// Determines if the destination page will be a Community Toolkit . - /// - /// The current . - /// A boolean indicating if the destination page will be a Community Toolkit . - public static bool IsDestinationPageACommunityToolkitPopupPage(this NavigatingFromEventArgs args) => args.DestinationPage is PopupPage; -} diff --git a/src/CommunityToolkit.Maui/Extensions/NavigationEventArgsExtensions.cs b/src/CommunityToolkit.Maui/Extensions/NavigationEventArgsExtensions.cs new file mode 100644 index 0000000000..041c520a9d --- /dev/null +++ b/src/CommunityToolkit.Maui/Extensions/NavigationEventArgsExtensions.cs @@ -0,0 +1,30 @@ +using CommunityToolkit.Maui.Views; + +namespace CommunityToolkit.Maui.Extensions; + +/// +/// Extension methods for , , and . +/// +public static class NavigationEventArgsExtensions +{ + /// + /// Determines if the destination page is a Community Toolkit . + /// + /// The current . + /// A boolean indicating if the destination page is a Community Toolkit . + public static bool IsDestinationPageACommunityToolkitPopupPage(this NavigatedFromEventArgs args) => args.DestinationPage is PopupPage; + + /// + /// Determines whether the previous page was a Community Toolkit . + /// + /// The current . + /// A boolean indicating whether the previous page was a Community Toolkit . + public static bool WasPreviousPageACommunityToolkitPopupPage(this NavigatedToEventArgs args) => args.PreviousPage is PopupPage; + + /// + /// Determines if the destination page will be a Community Toolkit . + /// + /// The current . + /// A boolean indicating if the destination page will be a Community Toolkit . + public static bool IsDestinationPageACommunityToolkitPopupPage(this NavigatingFromEventArgs args) => args.DestinationPage is PopupPage; +} \ No newline at end of file From 90cdcef3c49b4eec8f5894f6bc1cf7c02d75c707 Mon Sep 17 00:00:00 2001 From: Brandon Minnick <13558917+TheCodeTraveler@users.noreply.github.com> Date: Wed, 18 Feb 2026 10:17:56 -0800 Subject: [PATCH 4/5] Ensure Unit Tests unsubscribe from event handler --- .../NavigatedFromEventArgsExtensionsTests.cs | 1 + .../NavigatedToEventArgsExtensionsTests.cs | 1 + .../NavigatingFromEventArgsExtensionsTests.cs | 44 ++++++++++++------- 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/CommunityToolkit.Maui.UnitTests/Extensions/NavigatedFromEventArgsExtensionsTests.cs b/src/CommunityToolkit.Maui.UnitTests/Extensions/NavigatedFromEventArgsExtensionsTests.cs index 61b83d5f5a..3bb9277845 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Extensions/NavigatedFromEventArgsExtensionsTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Extensions/NavigatedFromEventArgsExtensionsTests.cs @@ -36,6 +36,7 @@ public async Task NavigatedFromEventArgsExtensions_IsDestinationPageACommunityTo void HandleNavigatedFromEventArgsReceived(object? sender, NavigatedFromEventArgs e) { + shellContentPage.NavigatedFromEventArgsReceived -= HandleNavigatedFromEventArgsReceived; isDestinationPageACommunityToolkitPopupPageTCS.SetResult(e.IsDestinationPageACommunityToolkitPopupPage()); } } diff --git a/src/CommunityToolkit.Maui.UnitTests/Extensions/NavigatedToEventArgsExtensionsTests.cs b/src/CommunityToolkit.Maui.UnitTests/Extensions/NavigatedToEventArgsExtensionsTests.cs index dcdc34a086..2ffc7c1460 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Extensions/NavigatedToEventArgsExtensionsTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Extensions/NavigatedToEventArgsExtensionsTests.cs @@ -38,6 +38,7 @@ void HandleNavigatedToEventArgsReceived(object? sender, NavigatedToEventArgs e) { if (e.PreviousPage != mainPage) { + shellContentPage.NavigatedToEventArgsReceived -= HandleNavigatedToEventArgsReceived; wasPreviousPageACommunityToolkitPopupPageTCS.SetResult(e.WasPreviousPageACommunityToolkitPopupPage()); } } diff --git a/src/CommunityToolkit.Maui.UnitTests/Extensions/NavigatingFromEventArgsExtensionsTests.cs b/src/CommunityToolkit.Maui.UnitTests/Extensions/NavigatingFromEventArgsExtensionsTests.cs index ca25656cc6..023f5cb6ce 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Extensions/NavigatingFromEventArgsExtensionsTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Extensions/NavigatingFromEventArgsExtensionsTests.cs @@ -10,24 +10,20 @@ public class NavigatingFromEventArgsExtensionsTests : BaseViewTest public async Task NavigatingFromEventArgsExtensions_IsDestinationPageACommunityToolkitPopupPage_ShouldReturnTrue() { // Arrange - MockApplication application = (MockApplication)ServiceProvider.GetRequiredService(); - IPopupService popupService = ServiceProvider.GetRequiredService(); + TaskCompletionSource isDestinationPageACommunityToolkitPopupPageTCS = new(); + var application = (MockApplication)ServiceProvider.GetRequiredService(); + var popupService = ServiceProvider.GetRequiredService(); - Shell shell = (Shell)(application.Windows[0].Page ?? throw new InvalidOperationException("Unable to retrieve Shell")); - Page mainPage = shell.CurrentPage; - ShellContentPage shellContentPage = new(); + var shell = (Shell)(application.Windows[0].Page ?? throw new InvalidOperationException("Unable to retrieve Shell")); + var mainPage = shell.CurrentPage; + var shellContentPage = new ShellContentPage(); + shellContentPage.NavigatingFromEventArgsReceived += HandleNavigatingFromEventArgsReceived; - Dictionary shellParameters = new() + var shellParameters = new Dictionary { { nameof(ContentPage.BackgroundColor), Colors.Orange } }; - TaskCompletionSource isDestinationPageACommunityToolkitPopupPageTCS = new(); - shellContentPage.NavigatingFromEventArgsReceived += (sender, args) => - { - isDestinationPageACommunityToolkitPopupPageTCS.SetResult(args.IsDestinationPageACommunityToolkitPopupPage()); - }; - // Act await mainPage.Navigation.PushAsync(shellContentPage); await popupService.ShowPopupAsync(shell, null, shellParameters, TestContext.Current.CancellationToken); @@ -35,6 +31,17 @@ public async Task NavigatingFromEventArgsExtensions_IsDestinationPageACommunityT // Assert Assert.True(isDestinationPageACommunityToolkitPopupPage); + + void HandleNavigatingFromEventArgsReceived(object? sender, NavigatingFromEventArgs e) + { + ArgumentNullException.ThrowIfNull(sender); + + if (sender is not ShellContentPage) + { + shellContentPage.NavigatingFromEventArgsReceived -= HandleNavigatingFromEventArgsReceived; + isDestinationPageACommunityToolkitPopupPageTCS.SetResult(e.IsDestinationPageACommunityToolkitPopupPage()); + } + } } [Fact] @@ -51,10 +58,7 @@ public async Task NavigatingFromEventArgsExtensions_IsDestinationPageACommunityT ShellContentPage anotherShellContentPage = new(); TaskCompletionSource isDestinationPageACommunityToolkitPopupPageTCS = new(); - shellContentPage.NavigatingFromEventArgsReceived += (sender, args) => - { - isDestinationPageACommunityToolkitPopupPageTCS.SetResult(args.IsDestinationPageACommunityToolkitPopupPage()); - }; + shellContentPage.NavigatingFromEventArgsReceived += HandleNavigatingFromEventArgsReceived; // Act await mainPage.Navigation.PushAsync(shellContentPage); @@ -63,6 +67,14 @@ public async Task NavigatingFromEventArgsExtensions_IsDestinationPageACommunityT // Assert Assert.False(isDestinationPageACommunityToolkitPopupPage); + + void HandleNavigatingFromEventArgsReceived(object? sender, NavigatingFromEventArgs e) + { + ArgumentNullException.ThrowIfNull(sender); + + shellContentPage.NavigatingFromEventArgsReceived -= HandleNavigatingFromEventArgsReceived; + isDestinationPageACommunityToolkitPopupPageTCS.SetResult(e.IsDestinationPageACommunityToolkitPopupPage()); + } } sealed class ShellContentPage : ContentPage From c6886acba0e44a689212a6d5e5fe412f7f0b2c46 Mon Sep 17 00:00:00 2001 From: Brandon Minnick <13558917+TheCodeTraveler@users.noreply.github.com> Date: Wed, 18 Feb 2026 10:18:14 -0800 Subject: [PATCH 5/5] Implement `OnNavigatingFrom` in `PopupsPage` --- .../Pages/Views/Popup/PopupsPage.xaml.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/samples/CommunityToolkit.Maui.Sample/Pages/Views/Popup/PopupsPage.xaml.cs b/samples/CommunityToolkit.Maui.Sample/Pages/Views/Popup/PopupsPage.xaml.cs index 076ef8e8b5..9bc18a4cd2 100644 --- a/samples/CommunityToolkit.Maui.Sample/Pages/Views/Popup/PopupsPage.xaml.cs +++ b/samples/CommunityToolkit.Maui.Sample/Pages/Views/Popup/PopupsPage.xaml.cs @@ -33,6 +33,15 @@ protected override async void OnNavigatedFrom(NavigatedFromEventArgs args) { base.OnNavigatedFrom(args); if (args.IsDestinationPageACommunityToolkitPopupPage()) + { + await Toast.Make("Popup Opened").Show(); + } + } + + protected override async void OnNavigatingFrom(NavigatingFromEventArgs args) + { + base.OnNavigatingFrom(args); + if (args.IsDestinationPageACommunityToolkitPopupPage()) { await Toast.Make("Opening Popup").Show(); }