/// <summary>
        /// Transitions out of the state. Calls to <see cref="TransitionIn"/> and <see cref="TransitionOut"/> are synchronized
        /// and only one will be executed at a time, the rest will be blocked and executed in FIFO order.
        /// </summary>
        /// <paramref name="useTransitions">If true, use defined storyboard animations in the transition</paramref>
        public override async Task TransitionOut(VisualTransitionType type, bool useTransitions = true)
        {
            // If it's a transition to self and the transition out should be omitted return
            if (type == VisualTransitionType.ToTheSameSetup &&
                !(await GetRepeatedTransition()).HasFlag(RepeatedTransitionBehavior.TransitionOut))
            {
                return;
            }

            // Get into the semaphore
            await _TransitionSemaphore.WaitAsync();

            // Reset the temporary setters
            DispatcherHelpers.RunAsync(() => TemporarySetters.ForEach((x) => x.Reset()));

            if (useTransitions)
            {
                bool sbDefined = false;

                // Get on the UI thread
                await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                {
                    // If the storyboard is defined
                    if (TransitionOutStoryboard.WillComplete())
                    {
                        sbDefined = true;

                        // Run it
                        TransitionOutStoryboard?.Begin();
                    }
                });

                // If the UI thread task determined that storyboard was defined, start a task that will wait for the storyboard to finish
                if (sbDefined)
                {
                    await Task.Run(() => _WaitForStoryboardToFinish.WaitOne());
                }
            }

            // Transition finished; Release the semaphore
            _TransitionSemaphore.Release();
        }
Exemple #2
0
        /// <summary>
        /// Transitions out of the state. Cancels transition in operation (if it was happening).
        /// </summary>
        /// <param name="useTransitions"></param>
        /// <returns></returns>
        public override async Task TransitionOut(VisualTransitionType type, bool useTransitions = true)
        {
            // If there's already a transition out going on and we're not supposed to restart it, just return
            if (type == VisualTransitionType.ToTheSameSetup &&
                !(await GetRepeatedTransition()).HasFlag(RepeatedTransitionBehavior.TransitionOut))
            {
                return;
            }

            // If the CancellationTokenSource from the previous transition call is still alive cancel it
            _Cancellation?.Cancel();

            // Create a new source for ourselves
            var cancellation = new CancellationTokenSource();

            // And assign it to the class-wide variable
            _Cancellation = cancellation;

            // Reset the temporary setters
            DispatcherHelpers.RunAsync(() => TemporarySetters.ForEach((x) => x.Reset()));

            if (useTransitions)
            {
                bool sbDefined = false;

                // Get on the UI thread
                await DispatcherHelpers.RunAsync(() =>
                {
                    // If the storyboard is defined
                    if (TransitionOutStoryboard.WillComplete())
                    {
                        // signal it
                        sbDefined = true;

                        // Pause the transition in storyboard
                        TransitionInStoryboard?.Pause();
                        // Run the transition out storyboard
                        TransitionOutStoryboard?.Begin();
                    }
                });

                // If the UI thread task determined that storyboard was defined, start a task that will wait for the storyboard to finish
                if (sbDefined)
                {
                    // Wait either for cancellation or storyboard to finish so that this Task doesn't end before the operations
                    // are completed
                    if (await Task.Run(() => WaitHandle.WaitAny(new[] { cancellation.Token.WaitHandle, _WaitForStoryboard }) == 1))
                    {
                        // If we weren't cancelled remove the reference to the _Cancellation, otherwise the one cancelling
                        // will provide their own CancellationTokenSource therefore removing the reference to ours
                        _Cancellation = null;
                    }
                }
                else if (!cancellation.IsCancellationRequested)
                {
                    // If our cancellation was not removed by another call, remove the reference to it
                    _Cancellation = null;
                }
            }

            cancellation.Dispose();
        }