Skip to content

Commit 42f1f20

Browse files
jsuarezruizPureWeenrmarinho
authored
[Enhancement] Changes in navigation events parameters (#28384)
* Added repro sample * Added UITests * Changes in navigation events parameters * Fix failing UITest * Fixed test * Fixed test on iOS/Catalyst * Renamed NavigationType.PageSwap to NavigationType.Replace * Removed NavigationType.Initialized * Added two more samples, using tabs and flyout * Updated sample * Create Issue21814TabbedPage.cs * Updated flyout sample * Adding more tests * Added more TabbedPage tests * More FlyoutPage tests * Updated test * Fixed tests * Use Replace with Tabs and FlyoutItems * Fixed unit tests * Updated test * Fix iOS Flyout tests * Changes in tests * Fix test on Android * Fixed Windows test * Fixed parameters in NavigatingFromEventArgs * Updated TabbedPage unit test * Added more navigation unit tests * - fix publicapi.txt files * Update FlyoutPage.cs * Update FlyoutPage.cs * Update MultiPage.cs * - fix publicapi * More tests * Fixed device test * Changes based on PR feedback, simplify FlyoutPage Detail * More changes to fix a test * [ci] Update the publicapi * - remove navigatingfrom * Updated tests --------- Co-authored-by: Shane Neuville (HE/HIM) <[email protected]> Co-authored-by: Rui Marinho <[email protected]>
1 parent db10a7a commit 42f1f20

30 files changed

+1335
-85
lines changed

src/Controls/src/Core/FlyoutPage/FlyoutPage.cs

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,24 +53,44 @@ public Page Detail
5353
throw new InvalidOperationException("Detail must not already have a parent.");
5454

5555
var previousDetail = _detail;
56-
// TODO MAUI refine this to fire earlier
57-
_detail?.SendNavigatingFrom(new NavigatingFromEventArgs());
5856

57+
// Get the actual pages for navigation events (unwrap NavigationPages)
58+
var destinationPage =
59+
value is NavigationPage destinationNavPage ? destinationNavPage.CurrentPage : value;
60+
var previousPage = previousDetail is NavigationPage previousNavPage
61+
? previousNavPage.CurrentPage
62+
: previousDetail;
63+
64+
// Send NavigatingFrom event to the previous detail (if any)
65+
if (previousDetail is not null)
66+
{
67+
previousDetail.SendNavigatingFrom(new NavigatingFromEventArgs(destinationPage,
68+
NavigationType.Replace));
69+
}
70+
71+
// Update the detail property
5972
OnPropertyChanging();
60-
if (_detail != null)
73+
if (_detail is not null)
6174
InternalChildren.Remove(_detail);
6275
_detail = value;
6376
InternalChildren.Add(_detail);
6477
OnPropertyChanged();
6578

66-
if (this.HasAppeared)
79+
// Handle Appearing/Disappearing events if the FlyoutPage has appeared
80+
if (HasAppeared)
6781
{
6882
previousDetail?.SendDisappearing();
6983
_detail?.SendAppearing();
7084
}
7185

72-
previousDetail?.SendNavigatedFrom(new NavigatedFromEventArgs(_detail, NavigationType.PageSwap));
73-
_detail?.SendNavigatedTo(new NavigatedToEventArgs(previousDetail));
86+
// Send NavigatedFrom and NavigatedTo events
87+
if (previousDetail is not null)
88+
{
89+
previousDetail.SendNavigatedFrom(
90+
new NavigatedFromEventArgs(destinationPage, NavigationType.Replace));
91+
}
92+
93+
_detail.SendNavigatedTo(new NavigatedToEventArgs(previousPage, NavigationType.Replace));
7494
}
7595
}
7696

@@ -108,8 +128,9 @@ public Page Flyout
108128

109129
// TODO MAUI refine this to fire earlier
110130
var previousFlyout = _flyout;
131+
111132
// TODO MAUI refine this to fire earlier
112-
_flyout?.SendNavigatingFrom(new NavigatingFromEventArgs());
133+
previousFlyout?.SendNavigatingFrom(new NavigatingFromEventArgs(value, NavigationType.Replace));
113134

114135
OnPropertyChanging();
115136
if (_flyout != null)
@@ -123,9 +144,9 @@ public Page Flyout
123144
previousFlyout?.SendDisappearing();
124145
_flyout?.SendAppearing();
125146
}
126-
127-
previousFlyout?.SendNavigatedFrom(new NavigatedFromEventArgs(_flyout, NavigationType.PageSwap));
128-
_flyout?.SendNavigatedTo(new NavigatedToEventArgs(previousFlyout));
147+
148+
previousFlyout?.SendNavigatedFrom(new NavigatedFromEventArgs(_flyout, NavigationType.Replace));
149+
_flyout?.SendNavigatedTo(new NavigatedToEventArgs(previousFlyout, NavigationType.Replace));
129150
}
130151
}
131152

src/Controls/src/Core/MultiPage.cs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,15 @@ public T CurrentPage
8383

8484
var previousPage = _current;
8585
OnPropertyChanging();
86-
86+
8787
// TODO: MAUI refine this to fire earlier
88-
_current?.SendNavigatingFrom(new NavigatingFromEventArgs());
89-
88+
89+
// Send NavigatingFrom to the previous page or to the new page if no previous page exists
90+
if (_current is not null)
91+
{
92+
_current.SendNavigatingFrom(new NavigatingFromEventArgs(value, NavigationType.Replace));
93+
}
94+
9095
_current = value;
9196

9297
previousPage?.SendDisappearing();
@@ -96,9 +101,10 @@ public T CurrentPage
96101

97102
if (HasAppeared)
98103
_current?.SendAppearing();
99-
100-
previousPage?.SendNavigatedFrom(new NavigatedFromEventArgs(_current, NavigationType.PageSwap));
101-
_current?.SendNavigatedTo(new NavigatedToEventArgs(previousPage));
104+
105+
106+
previousPage?.SendNavigatedFrom(new NavigatedFromEventArgs(_current, NavigationType.Replace));
107+
_current?.SendNavigatedTo(new NavigatedToEventArgs(previousPage, NavigationType.Replace));
102108
}
103109
}
104110

@@ -377,4 +383,4 @@ void UpdateCurrentPage()
377383
CurrentPage = (T)SelectedItem;
378384
}
379385
}
380-
}
386+
}

src/Controls/src/Core/NavigationModel.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ public Page PopModal()
113113
_navTree[0].Count > 0 &&
114114
_navTree[0][0] is not Shell)
115115
{
116-
previousPage.SendNavigatingFrom(new NavigatingFromEventArgs());
116+
previousPage.SendNavigatingFrom(new NavigatingFromEventArgs(CurrentPage, NavigationType.Pop));
117117
previousPage.SendDisappearing();
118118
CurrentPage.SendAppearing();
119119
}
@@ -201,7 +201,7 @@ public void PushModal(Page page)
201201
_navTree[0].Count > 0 &&
202202
_navTree[0][0] is not Shell)
203203
{
204-
previousPage.SendNavigatingFrom(new NavigatingFromEventArgs());
204+
previousPage.SendNavigatingFrom(new NavigatingFromEventArgs(page, NavigationType.Push));
205205
previousPage.SendDisappearing();
206206
page.SendAppearing();
207207
}

src/Controls/src/Core/NavigationPage/NavigationPage.Legacy.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ async Task<Page> PopAsyncInner(
2525

2626
var page = (Page)InternalChildren.Last();
2727
var previousPage = CurrentPage;
28-
SendNavigating();
28+
SendNavigating(NavigationType.Pop, previousPage);
2929
var removedPage = await RemoveAsyncInner(page, animated, fast);
3030
SendNavigated(previousPage, NavigationType.Pop);
3131
return removedPage;
@@ -150,7 +150,7 @@ async Task PopToRootAsyncInner(bool animated)
150150
return;
151151

152152
var previousPage = CurrentPage;
153-
SendNavigating();
153+
SendNavigating(NavigationType.PopToRoot, previousPage);
154154
FireDisappearing(CurrentPage);
155155
FireAppearing((Page)InternalChildren[0]);
156156

@@ -183,7 +183,9 @@ async Task PushAsyncInner(Page page, bool animated)
183183
return;
184184

185185
var previousPage = CurrentPage;
186-
SendNavigating();
186+
var navigationType = DetermineNavigationType();
187+
188+
SendNavigating(navigationType, previousPage);
187189
FireDisappearing(CurrentPage);
188190
FireAppearing(page);
189191

@@ -198,9 +200,9 @@ async Task PushAsyncInner(Page page, bool animated)
198200

199201
if (args.Task != null)
200202
await args.Task;
201-
}
202-
203-
SendNavigated(previousPage, NavigationType.Push);
203+
}
204+
205+
SendNavigated(previousPage, navigationType);
204206
Pushed?.Invoke(this, args);
205207
}
206208

src/Controls/src/Core/NavigationPage/NavigationPage.cs

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ public partial class NavigationPage : Page, IPageContainer<Page>, IBarElement, I
5454

5555
INavigationPageController NavigationPageController => this;
5656

57+
5758
partial void Init();
5859

5960
#if WINDOWS || ANDROID || TIZEN
@@ -63,6 +64,7 @@ public partial class NavigationPage : Page, IPageContainer<Page>, IBarElement, I
6364
#endif
6465

6566
bool _setForMaui;
67+
6668
/// <include file="../../docs/Microsoft.Maui.Controls/NavigationPage.xml" path="//Member[@MemberName='.ctor'][1]/Docs/*" />
6769
public NavigationPage() : this(UseMauiHandler)
6870
{
@@ -112,6 +114,8 @@ public Color BarTextColor
112114

113115
internal Task CurrentNavigationTask { get; set; }
114116

117+
internal NavigationType NavigationType { get; set; }
118+
115119
/// <include file="../../docs/Microsoft.Maui.Controls/NavigationPage.xml" path="//Member[@MemberName='Peek']/Docs/*" />
116120
[EditorBrowsable(EditorBrowsableState.Never)]
117121
public Page Peek(int depth)
@@ -377,12 +381,12 @@ protected override bool OnBackButtonPressed()
377381
void SendNavigated(Page previousPage, NavigationType navigationType)
378382
{
379383
previousPage?.SendNavigatedFrom(new NavigatedFromEventArgs(CurrentPage, navigationType));
380-
CurrentPage.SendNavigatedTo(new NavigatedToEventArgs(previousPage));
384+
CurrentPage.SendNavigatedTo(new NavigatedToEventArgs(previousPage, navigationType));
381385
}
382386

383-
void SendNavigating(Page navigatingFrom = null)
387+
void SendNavigating(NavigationType navigationType, Page navigatingFrom = null)
384388
{
385-
(navigatingFrom ?? CurrentPage)?.SendNavigatingFrom(new NavigatingFromEventArgs());
389+
(navigatingFrom ?? CurrentPage)?.SendNavigatingFrom(new NavigatingFromEventArgs(CurrentPage, navigationType));
386390
}
387391

388392

@@ -691,16 +695,17 @@ private protected override void OnHandlerChangedCore()
691695
var visiblePage = Navigation.NavigationStack[NavigationStack.Count - 1];
692696
RootPage = navStack[0];
693697
CurrentPage = visiblePage;
694-
698+
699+
var navigationType = DetermineNavigationType();
700+
695701
SendHandlerUpdateAsync(false, null,
696702
() =>
697703
{
698704
FireAppearing(CurrentPage);
699705
},
700706
() =>
701707
{
702-
// TODO this is the wrong navigation type
703-
SendNavigated(null, NavigationType.Initialize);
708+
SendNavigated(null, navigationType);
704709
})
705710
.FireAndForget(Handler);
706711
}
@@ -712,7 +717,21 @@ private protected override void OnHandlerChangedCore()
712717
((IStackNavigation)this).NavigationFinished(this.NavigationStack);
713718
}
714719
}
720+
721+
NavigationType DetermineNavigationType()
722+
{
723+
var parentPages = this.GetParentPages();
715724

725+
bool hasTabOrFlyout = parentPages.Any(page => page is FlyoutPage or TabbedPage);
726+
727+
if (hasTabOrFlyout)
728+
{
729+
return NavigationType.Replace;
730+
}
731+
732+
return NavigationType.Push;
733+
}
734+
716735
// Once we get all platforms over to the new APIs
717736
// we can just delete all the code inside NavigationPage.cs that fires "requested" events
718737
class MauiNavigationImpl : NavigationProxy
@@ -750,6 +769,7 @@ protected override void OnInsertPageBefore(Page page, Page before)
750769
Owner.SendHandlerUpdateAsync(false,
751770
() =>
752771
{
772+
Owner.NavigationType = NavigationType.Insert;
753773
int index = Owner.InternalChildren.IndexOf(before);
754774
Owner.InternalChildren.Insert(index, page);
755775

@@ -783,6 +803,7 @@ protected async override Task<Page> OnPopAsync(bool animated)
783803
await Owner.SendHandlerUpdateAsync(animated,
784804
() =>
785805
{
806+
Owner.NavigationType = NavigationType.Pop;
786807
Owner.CurrentPage = newCurrentPage;
787808
Owner.RemoveFromInnerChildren(currentPage);
788809
if (currentPage.TitleView != null)
@@ -792,7 +813,7 @@ await Owner.SendHandlerUpdateAsync(animated,
792813
},
793814
() =>
794815
{
795-
Owner.SendNavigating(currentPage);
816+
Owner.SendNavigating(NavigationType.Pop, currentPage);
796817
Owner.FireDisappearing(currentPage);
797818
Owner.FireAppearing(newCurrentPage);
798819
},
@@ -817,6 +838,7 @@ protected override Task OnPopToRootAsync(bool animated)
817838
return Owner.SendHandlerUpdateAsync(animated,
818839
() =>
819840
{
841+
Owner.NavigationType = NavigationType.PopToRoot;
820842
var lastIndex = NavigationStack.Count - 1;
821843
while (lastIndex > 0)
822844
{
@@ -829,7 +851,7 @@ protected override Task OnPopToRootAsync(bool animated)
829851
},
830852
() =>
831853
{
832-
Owner.SendNavigating(previousPage);
854+
Owner.SendNavigating(NavigationType.PopToRoot, previousPage);
833855
Owner.FireDisappearing(previousPage);
834856
Owner.FireAppearing(newPage);
835857
},
@@ -845,22 +867,24 @@ protected override Task OnPushAsync(Page root, bool animated)
845867
if (Owner.InternalChildren.Contains(root))
846868
return Task.CompletedTask;
847869

870+
var navigationType = Owner.DetermineNavigationType();
848871
var previousPage = Owner.CurrentPage;
849872

850873
return Owner.SendHandlerUpdateAsync(animated,
851874
() =>
852875
{
876+
Owner.NavigationType = navigationType;
853877
Owner.PushPage(root);
854878
},
855879
() =>
856880
{
857-
Owner.SendNavigating(previousPage);
881+
Owner.SendNavigating(navigationType, previousPage);
858882
Owner.FireDisappearing(previousPage);
859883
Owner.FireAppearing(root);
860884
},
861885
() =>
862886
{
863-
Owner.SendNavigated(previousPage, NavigationType.Push);
887+
Owner.SendNavigated(previousPage, navigationType);
864888
Owner?.Pushed?.Invoke(Owner, new NavigationEventArgs(root));
865889
});
866890
}
@@ -886,6 +910,7 @@ protected override void OnRemovePage(Page page)
886910
Owner.SendHandlerUpdateAsync(false,
887911
() =>
888912
{
913+
Owner.NavigationType = NavigationType.Remove;
889914
Owner.RemoveFromInnerChildren(page);
890915

891916
if (Owner.RootPage == page)
Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,18 @@
11
#nullable disable
22
using System;
3-
using Microsoft.Maui.Controls.Internals;
43

54
namespace Microsoft.Maui.Controls
65
{
7-
internal enum NavigationType
8-
{
9-
Push,
10-
Pop,
11-
PopToRoot,
12-
Insert,
13-
Remove,
14-
PageSwap,
15-
Initialize
16-
}
17-
186
public sealed class NavigatedFromEventArgs : EventArgs
197
{
20-
internal NavigationType NavigationType { get; }
8+
public NavigationType NavigationType { get; }
219

22-
internal Page DestinationPage { get; }
10+
public Page DestinationPage { get; }
2311

2412
internal NavigatedFromEventArgs(Page destinationPage, NavigationType navigationType)
2513
{
2614
DestinationPage = destinationPage;
2715
NavigationType = navigationType;
2816
}
2917
}
30-
}
18+
}

src/Controls/src/Core/Page/NavigatedToEventArgs.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ namespace Microsoft.Maui.Controls
55
{
66
public sealed class NavigatedToEventArgs : EventArgs
77
{
8-
internal NavigatedToEventArgs(Page previousPage)
8+
internal NavigatedToEventArgs(Page previousPage, NavigationType navigationType)
99
{
1010
PreviousPage = previousPage;
11+
NavigationType = navigationType;
1112
}
1213

13-
internal Page PreviousPage { get; }
14+
public Page PreviousPage { get; }
15+
public NavigationType NavigationType { get; }
1416
}
1517
}

0 commit comments

Comments
 (0)