public sealed class LeaveConfirmation A departure guard that asks before unsaved changes are lost, and discards them only when the departure commits. Compose it into a ViewModel that implements INavigationDepartureGuard and forward INavigationDepartureGuard.CanDepartAsync to LeaveConfirmation.CanDepartAsync.
Remarks
A yes stands while the transition it allowed is unsettled: a guard that runs again for the same entry, for example when a parent transition asks a child's guard that a child transition already asked, does not ask again. When a later request supersedes that transition, the yes moves to the later request. When the transition commits, is rejected, is cancelled or fails, the yes ends and the next departure asks again. When a change in another region (rather than a later request) supersedes it, the yes also ends, so the user may be asked again.
discard runs at most once per yes, inside the commit turn of the departure, after the new navigation state is applied and before the regions raise PropertyChanged. It must not pump or await navigation.
LeaveConfirmation.CanDepartAsync continues on the caller's synchronization context, so a confirm delegate that a UI-thread guard calls (a message box or a modal dialog) runs on that thread.
Constructors
LeaveConfirmation
public LeaveConfirmation(Func<bool> hasUnsavedChanges, Func<NavigationDeparture, CancellationToken, ValueTask<bool>> confirm, Action? discard = null, bool askOnRetain = false) Creates a leave confirmation.
Parameters
hasUnsavedChangesReturns whether leaving would lose changes. It is called inside a model turn.
confirmAsks the user and returns whether to leave. It runs in the guard, outside model turns, with the guard's token, which is cancelled when the departure is superseded, cancelled or the navigator closes.
discardDiscards the changes. It runs in the commit turn of a confirmed departure, at most once per yes.
askOnRetainWhether to ask when the entry is only retained, for example when a push covers it. By default only a departure that retires the entry asks, because a retained entry keeps its state. With it, a confirmed push over the entry runs
discardwhen the push commits, although the entry stays in the history.
Methods
CanDepartAsync
public ValueTask<bool> CanDepartAsync(NavigationDeparture departure, CancellationToken cancellationToken) Decides a departure: allows a retaining departure unless askOnRetain is set, allows a departure that a standing yes covers, allows when there are no unsaved changes, and otherwise asks. A yes registers discard with NavigationDeparture.OnCommitted.
Parameters
departureThe departure the guard received.
cancellationTokenThe guard's token.
InDialog
public static LeaveConfirmation InDialog<TDialog>(NavigationRegion<TDialog> dialogs, Func<INavigationTarget<TDialog>> dialog, Func<bool> hasUnsavedChanges, Action? discard = null) where TDialog : class Creates a leave confirmation that asks with a dialog pushed for a Boolean result into dialogs. Only Completed with true confirms; a dismissal, a rejected push or false keeps the entry. The guard's token is passed to the push, so a superseded departure and a closing navigator dismiss the dialog.
Type parameters
TDialogThe dialog region's content type.
Parameters
dialogsThe region that presents the dialog.
dialogCreates the dialog's target, once per question.
hasUnsavedChangesReturns whether leaving would lose changes. It is called inside a model turn.
discardDiscards the changes in the commit turn of a confirmed departure.
Remarks
The dialog region must not be the guarded region, one of its ancestors or one of its descendants: the push would be NavigationRejection.Reentrant, its completion Dismissed, and the guard would veto. The dialog completes with NavigationEntryContext.CompleteAsync and cancels with NavigationEntryContext.DismissAsync.