File: Shell\ShellNavigatingEventArgs.cs
Web Access
Project: src\src\Controls\src\Core\Controls.Core.csproj (Microsoft.Maui.Controls)
#nullable disable
using System;
using System.Threading;
using System.Threading.Tasks;
 
namespace Microsoft.Maui.Controls
{
 
	/// <include file="../../../docs/Microsoft.Maui.Controls/ShellNavigatingEventArgs.xml" path="Type[@FullName='Microsoft.Maui.Controls.ShellNavigatingEventArgs']/Docs/*" />
	public class ShellNavigatingEventArgs : EventArgs
	{
		int _deferralCount;
		Func<Task> _deferralFinishedTask;
		TaskCompletionSource<bool> _deferredTaskCompletionSource;
		bool _deferralCompleted = false;
 
		/// <include file="../../../docs/Microsoft.Maui.Controls/ShellNavigatingEventArgs.xml" path="//Member[@MemberName='.ctor']/Docs/*" />
		public ShellNavigatingEventArgs(ShellNavigationState current, ShellNavigationState target, ShellNavigationSource source, bool canCancel)
		{
 
			_deferralFinishedTask = () => Task.CompletedTask;
			Current = current;
			Target = target;
			Source = source;
			CanCancel = canCancel;
			Animate = true;
		}
 
		/// <include file="../../../docs/Microsoft.Maui.Controls/ShellNavigatingEventArgs.xml" path="//Member[@MemberName='Current']/Docs/*" />
		public ShellNavigationState Current { get; }
 
		/// <include file="../../../docs/Microsoft.Maui.Controls/ShellNavigatingEventArgs.xml" path="//Member[@MemberName='Target']/Docs/*" />
		public ShellNavigationState Target { get; }
 
		/// <include file="../../../docs/Microsoft.Maui.Controls/ShellNavigatingEventArgs.xml" path="//Member[@MemberName='Source']/Docs/*" />
		public ShellNavigationSource Source { get; }
 
		/// <include file="../../../docs/Microsoft.Maui.Controls/ShellNavigatingEventArgs.xml" path="//Member[@MemberName='CanCancel']/Docs/*" />
		public bool CanCancel { get; }
 
		/// <include file="../../../docs/Microsoft.Maui.Controls/ShellNavigatingEventArgs.xml" path="//Member[@MemberName='Cancel']/Docs/*" />
		public bool Cancel()
		{
			if (!CanCancel)
				return false;
 
			Cancelled = true;
			return true;
		}
 
		/// <include file="../../../docs/Microsoft.Maui.Controls/ShellNavigatingEventArgs.xml" path="//Member[@MemberName='Cancelled']/Docs/*" />
		public bool Cancelled { get; private set; }
 
		/// <include file="../../../docs/Microsoft.Maui.Controls/ShellNavigatingEventArgs.xml" path="//Member[@MemberName='GetDeferral']/Docs/*" />
		public ShellNavigatingDeferral GetDeferral()
		{
			if (_deferralCompleted)
				throw new InvalidOperationException("Deferral has already been completed");
 
			if (!CanCancel)
				return null;
 
			DeferredEventArgs = true;
			var currentCount = Interlocked.Increment(ref _deferralCount);
			if (currentCount == 1)
			{
				_deferredTaskCompletionSource = new TaskCompletionSource<bool>();
			}
 
			return new ShellNavigatingDeferral(DecrementDeferral);
		}
 
		async void DecrementDeferral()
		{
			if (Interlocked.Decrement(ref _deferralCount) == 0)
			{
				_deferralCompleted = true;
 
				try
				{
					var task = _deferralFinishedTask();
					_deferralFinishedTask = null;
					await task;
					_deferredTaskCompletionSource.SetResult(!Cancelled);
				}
				catch (TaskCanceledException)
				{
					_deferredTaskCompletionSource.SetCanceled();
				}
				catch (Exception exc)
				{
					_deferredTaskCompletionSource.SetException(exc);
				}
 
				_deferredTaskCompletionSource = null;
			}
		}
 
		internal Task<bool> DeferredTask => _deferredTaskCompletionSource?.Task;
		internal bool Animate { get; set; }
		internal bool DeferredEventArgs { get; set; }
 
		internal int DeferralCount => _deferralCount;
 
		internal bool NavigationDelayedOrCancelled =>
			Cancelled || DeferralCount > 0;
 
		internal void RegisterDeferralCompletedCallBack(Func<Task> deferralFinishedTask)
		{
			_deferralFinishedTask = deferralFinishedTask;
		}
	}
}