@ -43,6 +43,7 @@ namespace Avalonia.Controls
private ContentPresenter ? _ pagePresenter ;
private ContentPresenter ? _ pageBackPresenter ;
private CancellationTokenSource ? _ currentTransition ;
private Task _l astPageTransitionTask = Task . CompletedTask ;
private CancellationTokenSource ? _ currentModalTransition ;
private Border ? _ navBar ;
private Border ? _ navBarShadow ;
@ -769,15 +770,13 @@ namespace Avalonia.Controls
page . SetInNavigationPage ( true ) ;
UpdateActivePage ( ) ;
previousPage ? . SendNavigatedFrom ( new NavigatedFromEventArgs ( page , NavigationType . Push ) ) ;
page . SendNavigatedTo ( new NavigatedToEventArgs ( previousPage , NavigationType . Push ) ) ;
Pushed ? . Invoke ( this , new NavigationEventArgs ( page , NavigationType . Push ) ) ;
}
/// <summary>
/// Performs the stack mutation and lifecycle events for a pop. The visual transition runs
/// subsequently via <see cref="UpdateActivePage"/>.
/// Performs the stack mutation for a pop. The visual transition runs
/// subsequently via <see cref="UpdateActivePage"/>. Callers are responsible
/// for firing lifecycle events via <see cref="SendPopLifecycleEvents"/>
/// after awaiting the page transition where possible.
/// </summary>
private Page ? ExecutePopCore ( )
{
@ -810,11 +809,6 @@ namespace Avalonia.Controls
{
old . Navigation = null ;
old . SetInNavigationPage ( false ) ;
var newCurrentPage = CurrentPage ;
old . SendNavigatedFrom ( new NavigatedFromEventArgs ( newCurrentPage , NavigationType . Pop ) ) ;
newCurrentPage ? . SendNavigatedTo ( new NavigatedToEventArgs ( old , NavigationType . Pop ) ) ;
Popped ? . Invoke ( this , new NavigationEventArgs ( old , NavigationType . Pop ) ) ;
}
return old ;
@ -844,6 +838,12 @@ namespace Avalonia.Controls
}
ExecutePushCore ( page , previousPage ) ;
await AwaitPageTransitionAsync ( ) ;
previousPage ? . SendNavigatedFrom ( new NavigatedFromEventArgs ( page , NavigationType . Push ) ) ;
page . SendNavigatedTo ( new NavigatedToEventArgs ( previousPage , NavigationType . Push ) ) ;
Pushed ? . Invoke ( this , new NavigationEventArgs ( page , NavigationType . Push ) ) ;
}
finally
{
@ -886,7 +886,14 @@ namespace Avalonia.Controls
return null ;
}
return ExecutePopCore ( ) ;
var old = ExecutePopCore ( ) ;
await AwaitPageTransitionAsync ( ) ;
if ( old ! = null )
SendPopLifecycleEvents ( old , NavigationType . Pop ) ;
return old ;
}
finally
{
@ -931,6 +938,7 @@ namespace Avalonia.Controls
}
bool isIncc = Pages is INotifyCollectionChanged ;
var poppedPages = new List < Page > ( ) ;
void TearDownPopped ( Page popped )
{
@ -939,8 +947,7 @@ namespace Avalonia.Controls
LogicalChildren . Remove ( poppedLogical ) ;
popped . Navigation = null ;
popped . SetInNavigationPage ( false ) ;
popped . SendNavigatedFrom ( new NavigatedFromEventArgs ( rootPage , NavigationType . PopToRoot ) ) ;
Popped ? . Invoke ( this , new NavigationEventArgs ( popped , NavigationType . PopToRoot ) ) ;
poppedPages . Add ( popped ) ;
}
if ( Pages is Stack < Page > stack )
@ -962,6 +969,14 @@ namespace Avalonia.Controls
_ isPop = true ;
UpdateActivePage ( ) ;
await AwaitPageTransitionAsync ( ) ;
foreach ( var popped in poppedPages )
{
popped . SendNavigatedFrom ( new NavigatedFromEventArgs ( rootPage , NavigationType . PopToRoot ) ) ;
Popped ? . Invoke ( this , new NavigationEventArgs ( popped , NavigationType . PopToRoot ) ) ;
}
var newCurrentPage = CurrentPage ;
if ( newCurrentPage ! = null )
@ -1013,6 +1028,7 @@ namespace Avalonia.Controls
}
bool isIncc = Pages is INotifyCollectionChanged ;
var poppedPages = new List < Page > ( ) ;
void TearDownPopped ( Page popped )
{
@ -1021,8 +1037,7 @@ namespace Avalonia.Controls
LogicalChildren . Remove ( poppedLogical ) ;
popped . Navigation = null ;
popped . SetInNavigationPage ( false ) ;
popped . SendNavigatedFrom ( new NavigatedFromEventArgs ( page , NavigationType . Pop ) ) ;
Popped ? . Invoke ( this , new NavigationEventArgs ( popped , NavigationType . Pop ) ) ;
poppedPages . Add ( popped ) ;
}
if ( Pages is Stack < Page > stack )
@ -1044,6 +1059,14 @@ namespace Avalonia.Controls
_ isPop = true ;
UpdateActivePage ( ) ;
await AwaitPageTransitionAsync ( ) ;
foreach ( var popped in poppedPages )
{
popped . SendNavigatedFrom ( new NavigatedFromEventArgs ( page , NavigationType . Pop ) ) ;
Popped ? . Invoke ( this , new NavigationEventArgs ( popped , NavigationType . Pop ) ) ;
}
var newCurrentPage = CurrentPage ;
if ( newCurrentPage ! = null )
{
@ -1356,7 +1379,9 @@ namespace Avalonia.Controls
{
if ( stack . Count > 0 & & ReferenceEquals ( stack . Peek ( ) , page ) )
{
ExecutePopCore ( ) ;
var old = ExecutePopCore ( ) ;
if ( old ! = null )
SendPopLifecycleEvents ( old , NavigationType . Pop ) ;
PageRemoved ? . Invoke ( this , new PageRemovedEventArgs ( page ) ) ;
return ;
}
@ -1387,7 +1412,9 @@ namespace Avalonia.Controls
if ( idx = = list . Count - 1 )
{
ExecutePopCore ( ) ;
var old = ExecutePopCore ( ) ;
if ( old ! = null )
SendPopLifecycleEvents ( old , NavigationType . Pop ) ;
PageRemoved ? . Invoke ( this , new PageRemovedEventArgs ( page ) ) ;
return ;
}
@ -1595,12 +1622,14 @@ namespace Avalonia.Controls
oldPresenter . ZIndex = 0 ;
}
_ = RunPageTransitionAsync ( resolvedTransition , oldPresenter , newPresenter , ! isPop , cancel . Token ) ;
_l astPageTransitionTask = RunPageTransitionAsync ( resolvedTransition , oldPresenter , newPresenter , ! isPop , cancel . Token ) ;
( _ pagePresenter , _ pageBackPresenter ) = ( newPresenter , oldPresenter ) ;
}
else
{
_l astPageTransitionTask = Task . CompletedTask ;
_ pagePresenter . Content = page ;
_ pagePresenter . IsVisible = page ! = null ;
_ pagePresenter . ZIndex = 0 ;
@ -1686,6 +1715,25 @@ namespace Avalonia.Controls
from . Opacity = 1 ;
}
private Task AwaitPageTransitionAsync ( )
{
var task = _l astPageTransitionTask ;
_l astPageTransitionTask = Task . CompletedTask ;
return task ;
}
/// <summary>
/// Fires lifecycle events after a pop: SendNavigatedFrom on the old page,
/// SendNavigatedTo on the new current page, and raises the Popped event.
/// </summary>
private void SendPopLifecycleEvents ( Page oldPage , NavigationType navigationType )
{
var newCurrentPage = CurrentPage ;
oldPage . SendNavigatedFrom ( new NavigatedFromEventArgs ( newCurrentPage , navigationType ) ) ;
newCurrentPage ? . SendNavigatedTo ( new NavigatedToEventArgs ( oldPage , navigationType ) ) ;
Popped ? . Invoke ( this , new NavigationEventArgs ( oldPage , navigationType ) ) ;
}
/// <summary>
/// Swaps the top of the navigation stack with <paramref name="page"/>.
/// </summary>