From 9677d47fd62478e0255380da4283ba8145026220 Mon Sep 17 00:00:00 2001 From: rlittlesii <6969701+RLittlesII@users.noreply.github.com> Date: Wed, 22 May 2024 20:15:28 -0500 Subject: [PATCH 1/7] fix: GetCurrentPage for PrismWindow.Page throwing exception add test cleaned up some white space --- src/Maui/Prism.Maui/Common/MvvmHelpers.cs | 10 ++++++++- .../Fixtures/Common/MvvmHelperFixture.cs | 21 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/Maui/Prism.Maui.Tests/Fixtures/Common/MvvmHelperFixture.cs diff --git a/src/Maui/Prism.Maui/Common/MvvmHelpers.cs b/src/Maui/Prism.Maui/Common/MvvmHelpers.cs index 625879d6b..042ec4938 100644 --- a/src/Maui/Prism.Maui/Common/MvvmHelpers.cs +++ b/src/Maui/Prism.Maui/Common/MvvmHelpers.cs @@ -88,12 +88,14 @@ private static void DestroyChildren(IView page) { DestroyPage(item); } + break; case NavigationPage navigationPage: foreach (var item in navigationPage.Navigation.NavigationStack.Reverse()) { DestroyPage(item); } + break; } } @@ -104,11 +106,12 @@ public static void DestroyWithModalStack(Page? page, IList modalStack) { DestroyPage(childPage); } + DestroyPage(page); } public static T? GetImplementerFromViewOrViewModel(object view) - where T : class + where T : class { if (view is T viewAsT) { @@ -303,6 +306,11 @@ public static void SetCurrentPageDelegate(Func getCurrentPageDelega return GetTarget(parentPage); } + if (page.Parent is PrismWindow prismWindow) + { + return GetTarget(prismWindow.Page); + } + throw new InvalidOperationException("Unable to determine the current page."); } diff --git a/tests/Maui/Prism.Maui.Tests/Fixtures/Common/MvvmHelperFixture.cs b/tests/Maui/Prism.Maui.Tests/Fixtures/Common/MvvmHelperFixture.cs new file mode 100644 index 000000000..48b195e70 --- /dev/null +++ b/tests/Maui/Prism.Maui.Tests/Fixtures/Common/MvvmHelperFixture.cs @@ -0,0 +1,21 @@ +using Prism.Common; + +namespace Prism.Maui.Tests.Fixtures.Common; + +public class MvvmHelperFixture +{ + [Fact] + public async Task GetCurrentPageWithModalReturnsPrismWindowPage() + { + // Given + var contentPage = new ContentPage(); + var prismWindow = new PrismWindow { Page = contentPage }; + await prismWindow.Navigation.PushModalAsync(new DialogContainerPage()); + + // When + var result = MvvmHelpers.GetCurrentPage(prismWindow.Page); + + // Then + Assert.Equal(result, contentPage); + } +} From b6ddf02667d8c392a4d8662b5f17e04576038b65 Mon Sep 17 00:00:00 2001 From: rlittlesii <6969701+RLittlesII@users.noreply.github.com> Date: Fri, 24 May 2024 12:46:57 -0500 Subject: [PATCH 2/7] switched to expression --- src/Maui/Prism.Maui/Common/MvvmHelpers.cs | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/Maui/Prism.Maui/Common/MvvmHelpers.cs b/src/Maui/Prism.Maui/Common/MvvmHelpers.cs index 042ec4938..907a6119d 100644 --- a/src/Maui/Prism.Maui/Common/MvvmHelpers.cs +++ b/src/Maui/Prism.Maui/Common/MvvmHelpers.cs @@ -299,23 +299,10 @@ public static void SetCurrentPageDelegate(Func getCurrentPageDelega if (target is { } page) { - if (target is IDialogContainer) - { - if (page.Parent is Page parentPage) - { - return GetTarget(parentPage); - } - - if (page.Parent is PrismWindow prismWindow) - { - return GetTarget(prismWindow.Page); - } - - throw new InvalidOperationException("Unable to determine the current page."); - } - return page.Parent switch { + Page parent when page is IDialogContainer => GetTarget(parent), + PrismWindow prismWindow when page is IDialogContainer => GetTarget(prismWindow.Page), TabbedPage tab when tab.CurrentPage != target => EvaluateCurrentPage(tab.CurrentPage), NavigationPage nav when nav.CurrentPage != target => EvaluateCurrentPage(nav.CurrentPage), _ => target From 80d9d914cd7613f41a24e960e09335631c850d33 Mon Sep 17 00:00:00 2001 From: rlittlesii <6969701+RLittlesII@users.noreply.github.com> Date: Fri, 24 May 2024 13:54:42 -0500 Subject: [PATCH 3/7] Dan wants the exception --- src/Maui/Prism.Maui/Common/MvvmHelpers.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Maui/Prism.Maui/Common/MvvmHelpers.cs b/src/Maui/Prism.Maui/Common/MvvmHelpers.cs index 907a6119d..6eccd1c0e 100644 --- a/src/Maui/Prism.Maui/Common/MvvmHelpers.cs +++ b/src/Maui/Prism.Maui/Common/MvvmHelpers.cs @@ -299,10 +299,18 @@ public static void SetCurrentPageDelegate(Func getCurrentPageDelega if (target is { } page) { + if (target is IDialogContainer) + { + return page.Parent switch + { + Page parentPage => GetTarget(parentPage), + PrismWindow prismWindow => GetTarget(prismWindow.Page), + _ => throw new InvalidOperationException("Unable to determine the current page.") + }; + } + return page.Parent switch { - Page parent when page is IDialogContainer => GetTarget(parent), - PrismWindow prismWindow when page is IDialogContainer => GetTarget(prismWindow.Page), TabbedPage tab when tab.CurrentPage != target => EvaluateCurrentPage(tab.CurrentPage), NavigationPage nav when nav.CurrentPage != target => EvaluateCurrentPage(nav.CurrentPage), _ => target From 997a0bdc03764b1d18258b6f1e79120c085ac61a Mon Sep 17 00:00:00 2001 From: rlittlesii <6969701+RLittlesII@users.noreply.github.com> Date: Fri, 24 May 2024 13:57:37 -0500 Subject: [PATCH 4/7] Window has a Page! --- src/Maui/Prism.Maui/Common/MvvmHelpers.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Maui/Prism.Maui/Common/MvvmHelpers.cs b/src/Maui/Prism.Maui/Common/MvvmHelpers.cs index 6eccd1c0e..49a76b31b 100644 --- a/src/Maui/Prism.Maui/Common/MvvmHelpers.cs +++ b/src/Maui/Prism.Maui/Common/MvvmHelpers.cs @@ -304,7 +304,7 @@ public static void SetCurrentPageDelegate(Func getCurrentPageDelega return page.Parent switch { Page parentPage => GetTarget(parentPage), - PrismWindow prismWindow => GetTarget(prismWindow.Page), + Window window => GetTarget(window.Page), _ => throw new InvalidOperationException("Unable to determine the current page.") }; } From a9d344e235da26d2eb49c67a571550facb3e56bb Mon Sep 17 00:00:00 2001 From: rlittlesii <6969701+RLittlesII@users.noreply.github.com> Date: Fri, 24 May 2024 14:22:52 -0500 Subject: [PATCH 5/7] convert fact to theory --- src/Maui/Prism.Maui/Common/MvvmHelpers.cs | 3 +- .../Fixtures/Common/MvvmHelperFixture.cs | 42 +++++++++++++++---- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/Maui/Prism.Maui/Common/MvvmHelpers.cs b/src/Maui/Prism.Maui/Common/MvvmHelpers.cs index 49a76b31b..0754c73b9 100644 --- a/src/Maui/Prism.Maui/Common/MvvmHelpers.cs +++ b/src/Maui/Prism.Maui/Common/MvvmHelpers.cs @@ -284,8 +284,9 @@ public static void SetCurrentPageDelegate(Func getCurrentPageDelega { FlyoutPage flyout => GetTarget(flyout.Detail), TabbedPage tabbed => GetTarget(tabbed.CurrentPage), - NavigationPage navigation => GetTarget(navigation.CurrentPage), + NavigationPage navigation => GetTarget(navigation.CurrentPage) ?? navigation, ContentPage page => page, + null => null, _ => throw new NotSupportedException($"The page type '{target.GetType().FullName}' is not supported.") }; } diff --git a/tests/Maui/Prism.Maui.Tests/Fixtures/Common/MvvmHelperFixture.cs b/tests/Maui/Prism.Maui.Tests/Fixtures/Common/MvvmHelperFixture.cs index 48b195e70..90c3da0c4 100644 --- a/tests/Maui/Prism.Maui.Tests/Fixtures/Common/MvvmHelperFixture.cs +++ b/tests/Maui/Prism.Maui.Tests/Fixtures/Common/MvvmHelperFixture.cs @@ -1,21 +1,49 @@ +using System.Collections; using Prism.Common; +using Prism.Maui.Tests.Mocks.Views; namespace Prism.Maui.Tests.Fixtures.Common; public class MvvmHelperFixture { - [Fact] - public async Task GetCurrentPageWithModalReturnsPrismWindowPage() + /// + /// This test was introduced to verify GH3143 + /// + /// Git Hub Issue 3143 + /// The window representing the root of the navigation. + /// The actual page we expect to return. + /// The model page we are pushing on the stack that causes the problem. + [Theory] + [ClassData(typeof(GetCurrentPageTestData))] + public async Task GetCurrentPageWithModalReturnsPrismWindowPage(Window window, Page page, Page modal) { // Given - var contentPage = new ContentPage(); - var prismWindow = new PrismWindow { Page = contentPage }; - await prismWindow.Navigation.PushModalAsync(new DialogContainerPage()); + await window.Navigation.PushModalAsync(modal); // When - var result = MvvmHelpers.GetCurrentPage(prismWindow.Page); + var result = MvvmHelpers.GetCurrentPage(window.Page); // Then - Assert.Equal(result, contentPage); + Assert.Equal(result, page); + } + + private class GetCurrentPageTestData : IEnumerable + { + public IEnumerator GetEnumerator() + { + ContentPage contentPage = new ContentPage { Title = "Title" }; + NavigationPage navigationPage = new NavigationPage(); + // TabbedPage tabbedPage = new TabbedPage { CurrentPage = contentPage }; + FlyoutPage flyout = new FlyoutPage { Flyout = contentPage, Detail = new NavigationPage(), }; + DialogContainerPage dialogContainerPage = new DialogContainerPage(); + yield return new object[] { PrismWindow(contentPage), contentPage, dialogContainerPage }; + yield return new object[] { PrismWindow(navigationPage), navigationPage, dialogContainerPage }; + // yield return new object[] { PrismWindow(tabbedPage), tabbedPage, dialogContainerPage }; + yield return new object[] { PrismWindow(flyout), flyout.Detail, dialogContainerPage }; + } + + private static PrismWindow PrismWindow(Page page) => new() { Page = page }; + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } } From f757300b68b127069dfafead8edb1a449f23717b Mon Sep 17 00:00:00 2001 From: rlittlesii <6969701+RLittlesII@users.noreply.github.com> Date: Fri, 24 May 2024 17:05:26 -0500 Subject: [PATCH 6/7] separate tests clean up test naming ensuring bug is attached to each test --- .../Fixtures/Common/MvvmHelperFixture.cs | 98 ++++++++++++++----- 1 file changed, 72 insertions(+), 26 deletions(-) diff --git a/tests/Maui/Prism.Maui.Tests/Fixtures/Common/MvvmHelperFixture.cs b/tests/Maui/Prism.Maui.Tests/Fixtures/Common/MvvmHelperFixture.cs index 90c3da0c4..63846b6c7 100644 --- a/tests/Maui/Prism.Maui.Tests/Fixtures/Common/MvvmHelperFixture.cs +++ b/tests/Maui/Prism.Maui.Tests/Fixtures/Common/MvvmHelperFixture.cs @@ -1,6 +1,4 @@ -using System.Collections; using Prism.Common; -using Prism.Maui.Tests.Mocks.Views; namespace Prism.Maui.Tests.Fixtures.Common; @@ -10,40 +8,88 @@ public class MvvmHelperFixture /// This test was introduced to verify GH3143 /// /// Git Hub Issue 3143 - /// The window representing the root of the navigation. - /// The actual page we expect to return. - /// The model page we are pushing on the stack that causes the problem. - [Theory] - [ClassData(typeof(GetCurrentPageTestData))] - public async Task GetCurrentPageWithModalReturnsPrismWindowPage(Window window, Page page, Page modal) + [Fact] + public async Task GetCurrentPageFromFlyoutPageWithModalReturnsDetailPage() { // Given - await window.Navigation.PushModalAsync(modal); + FlyoutPage flyout = new FlyoutPage + { Flyout = new ContentPage { Title = "Title" }, Detail = new NavigationPage(), }; + PrismWindow window = new PrismWindow { Page = flyout }; + await window.Navigation.PushModalAsync(new DialogContainerPage()); // When var result = MvvmHelpers.GetCurrentPage(window.Page); // Then - Assert.Equal(result, page); + Assert.Equal(result, flyout.Detail); } - private class GetCurrentPageTestData : IEnumerable + /// + /// This test was introduced to verify GH3143 + /// + /// Git Hub Issue 3143 + [Fact] + public async Task GetCurrentPageFromComplexFlyoutPageWithModalReturnsCorrectPage() { - public IEnumerator GetEnumerator() + // Given + ContentPage current = new ContentPage { Title = "D" }; + var navigationPage = new NavigationPage(); + await navigationPage.PushAsync(new ContentPage { Title = "A" }); + await navigationPage.PushAsync(new ContentPage { Title = "B" }); + await navigationPage.PushAsync(new ContentPage { Title = "C" }); + await navigationPage.PushAsync(current); + + PrismWindow window = new PrismWindow { - ContentPage contentPage = new ContentPage { Title = "Title" }; - NavigationPage navigationPage = new NavigationPage(); - // TabbedPage tabbedPage = new TabbedPage { CurrentPage = contentPage }; - FlyoutPage flyout = new FlyoutPage { Flyout = contentPage, Detail = new NavigationPage(), }; - DialogContainerPage dialogContainerPage = new DialogContainerPage(); - yield return new object[] { PrismWindow(contentPage), contentPage, dialogContainerPage }; - yield return new object[] { PrismWindow(navigationPage), navigationPage, dialogContainerPage }; - // yield return new object[] { PrismWindow(tabbedPage), tabbedPage, dialogContainerPage }; - yield return new object[] { PrismWindow(flyout), flyout.Detail, dialogContainerPage }; - } - - private static PrismWindow PrismWindow(Page page) => new() { Page = page }; - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + Page = new FlyoutPage + { Flyout = new ContentPage { Title = "Title" }, Detail = navigationPage, } + }; + + await window.Navigation.PushModalAsync(new DialogContainerPage()); + + // When + var result = MvvmHelpers.GetCurrentPage(window.Page); + + // Then + Assert.Equal(result, current); + } + + /// + /// This test was introduced to verify GH3143 + /// + /// Git Hub Issue 3143 + [Fact] + public async Task GetCurrentPageFromNavigationPageWithModalReturnsContentPage() + { + // Given + var contentPage = new ContentPage(); + NavigationPage navigationPage = new NavigationPage(contentPage); + PrismWindow window = new PrismWindow { Page = navigationPage }; + await window.Navigation.PushModalAsync(new DialogContainerPage()); + + // When + var result = MvvmHelpers.GetCurrentPage(window.Page); + + // Then + Assert.Equal(result, contentPage); + } + + /// + /// This test was introduced to verify GH3143 + /// + /// Git Hub Issue 3143 + [Fact] + public async Task GetCurrentPageFromContentPageWithModalReturnsContentPage() + { + // Given + ContentPage contentPage = new ContentPage { Title = "Title" }; + PrismWindow window = new PrismWindow { Page = contentPage }; + await window.Navigation.PushModalAsync(new DialogContainerPage()); + + // When + var result = MvvmHelpers.GetCurrentPage(window.Page); + + // Then + Assert.Equal(result, contentPage); } } From c007c9fa4f906e34c45ac85f071b089fff5ad277 Mon Sep 17 00:00:00 2001 From: rlittlesii <6969701+RLittlesII@users.noreply.github.com> Date: Fri, 24 May 2024 17:26:56 -0500 Subject: [PATCH 7/7] add skipped tabbed page tests clean up expected vs actual --- .../Fixtures/Common/MvvmHelperFixture.cs | 68 +++++++++++++++---- 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/tests/Maui/Prism.Maui.Tests/Fixtures/Common/MvvmHelperFixture.cs b/tests/Maui/Prism.Maui.Tests/Fixtures/Common/MvvmHelperFixture.cs index 63846b6c7..83b7bd6c6 100644 --- a/tests/Maui/Prism.Maui.Tests/Fixtures/Common/MvvmHelperFixture.cs +++ b/tests/Maui/Prism.Maui.Tests/Fixtures/Common/MvvmHelperFixture.cs @@ -12,16 +12,16 @@ public class MvvmHelperFixture public async Task GetCurrentPageFromFlyoutPageWithModalReturnsDetailPage() { // Given - FlyoutPage flyout = new FlyoutPage + var flyout = new FlyoutPage { Flyout = new ContentPage { Title = "Title" }, Detail = new NavigationPage(), }; - PrismWindow window = new PrismWindow { Page = flyout }; + var window = new PrismWindow { Page = flyout }; await window.Navigation.PushModalAsync(new DialogContainerPage()); // When var result = MvvmHelpers.GetCurrentPage(window.Page); // Then - Assert.Equal(result, flyout.Detail); + Assert.Equal(flyout.Detail, result); } /// @@ -32,14 +32,14 @@ public async Task GetCurrentPageFromFlyoutPageWithModalReturnsDetailPage() public async Task GetCurrentPageFromComplexFlyoutPageWithModalReturnsCorrectPage() { // Given - ContentPage current = new ContentPage { Title = "D" }; + var expected = new ContentPage { Title = "D" }; var navigationPage = new NavigationPage(); await navigationPage.PushAsync(new ContentPage { Title = "A" }); await navigationPage.PushAsync(new ContentPage { Title = "B" }); await navigationPage.PushAsync(new ContentPage { Title = "C" }); - await navigationPage.PushAsync(current); + await navigationPage.PushAsync(expected); - PrismWindow window = new PrismWindow + var window = new Window { Page = new FlyoutPage { Flyout = new ContentPage { Title = "Title" }, Detail = navigationPage, } @@ -51,7 +51,7 @@ public async Task GetCurrentPageFromComplexFlyoutPageWithModalReturnsCorrectPage var result = MvvmHelpers.GetCurrentPage(window.Page); // Then - Assert.Equal(result, current); + Assert.Equal(expected, result); } /// @@ -62,16 +62,15 @@ public async Task GetCurrentPageFromComplexFlyoutPageWithModalReturnsCorrectPage public async Task GetCurrentPageFromNavigationPageWithModalReturnsContentPage() { // Given - var contentPage = new ContentPage(); - NavigationPage navigationPage = new NavigationPage(contentPage); - PrismWindow window = new PrismWindow { Page = navigationPage }; + var expected = new ContentPage(); + var window = new Window { Page = new NavigationPage(expected) }; await window.Navigation.PushModalAsync(new DialogContainerPage()); // When var result = MvvmHelpers.GetCurrentPage(window.Page); // Then - Assert.Equal(result, contentPage); + Assert.Equal(expected, result); } /// @@ -82,14 +81,55 @@ public async Task GetCurrentPageFromNavigationPageWithModalReturnsContentPage() public async Task GetCurrentPageFromContentPageWithModalReturnsContentPage() { // Given - ContentPage contentPage = new ContentPage { Title = "Title" }; - PrismWindow window = new PrismWindow { Page = contentPage }; + var expected = new ContentPage { Title = "Title" }; + var window = new Window { Page = expected }; await window.Navigation.PushModalAsync(new DialogContainerPage()); // When var result = MvvmHelpers.GetCurrentPage(window.Page); // Then - Assert.Equal(result, contentPage); + Assert.Equal(expected, result); + } + + /// + /// This test was introduced to verify GH3143 + /// + /// Git Hub Issue 3143 + [Fact(Skip = "System.InvalidOperationException\nBindableObject was not instantiated on a thread with a dispatcher nor does the current application have a dispatcher.")] + public async Task GetCurrentPageFromTabbedPageWithModalReturnsContentPage() + { + // Given + var expected = new ContentPage(); + var tabbedPage = new TabbedPage { Title = "Tab", Children = { expected }}; + var window = new Window { Page = tabbedPage }; + await window.Navigation.PushModalAsync(new DialogContainerPage()); + + // When + var result = MvvmHelpers.GetCurrentPage(window.Page); + + // Then + Assert.Equal(expected, result); + } + + /// + /// This test was introduced to verify GH3143 + /// + /// Git Hub Issue 3143 + [Fact(Skip = "System.InvalidOperationException\nBindableObject was not instantiated on a thread with a dispatcher nor does the current application have a dispatcher.")] + public async Task GetCurrentPageFromTabbedNavigationPageWithModalReturnsContentPage() + { + // Given + var expected = new ContentPage(); + var navigationPage = new NavigationPage(expected); + var tabbedPage = new TabbedPage { Title = "Tab", Children = { navigationPage }}; + var window = new Window { Page = tabbedPage }; + await window.Navigation.PushModalAsync(new DialogContainerPage()); + + // When + var result = MvvmHelpers.GetCurrentPage(window.Page); + + // Then + Assert.Equal(expected, result); } }