/// <summary>
        /// Hides a modal frame.
        /// </summary>
        /// <param name="previousFrameName">The name of the modal frame to close.</param>
        /// <param name="nextFrameName">The name of the frame that will be revealed as a result of closing the modal.</param>
        /// <param name="transitionInfo">The transition info describing the animation.</param>
        public async Task CloseModal(string previousFrameName, string nextFrameName, FrameSectionsTransitionInfo transitionInfo)         // Runs on background thread.
        {
            await HidePreviousFrameAndShowNextFrame(previousFrameName, nextFrameName, UpdateView);

            async Task UpdateView(FrameInfo previousFrame, FrameInfo nextFrame)             // Runs on the UI thread
            {
                switch (transitionInfo)
                {
                case DelegatingFrameSectionsTransitionInfo frameTransition:
                    await frameTransition.Run(frameToHide : previousFrame.Frame, frameToShow : nextFrame.Frame, frameToShowIsAboveFrameToHide : false);

                    break;

                case UIViewControllerSectionsTransitionInfo viewControllerTransitionInfo:
                    await previousFrame.ModalViewController.Close(viewControllerTransitionInfo);

                    break;

                default:
                    throw new InvalidOperationException($"Unsupported transition info type '{transitionInfo.GetType()}'.");
                }
            }
        }
        /// <summary>
        /// Changes the active section.
        /// </summary>
        /// <param name="previousFrameName">The name of the frame that will no longer be active.</param>
        /// <param name="nextFrameName">The name of the frame that will be active.</param>
        /// <param name="transitionInfo">The transition info describing the animation.</param>
        public async Task ChangeActiveSection(string previousFrameName, string nextFrameName, FrameSectionsTransitionInfo transitionInfo)         // Runs on background thread.
        {
            await HidePreviousFrameAndShowNextFrame(previousFrameName, nextFrameName, UpdateView);

            async Task UpdateView(FrameInfo previousFrame, FrameInfo nextFrame)             // Runs on the UI thread
            {
                switch (transitionInfo)
                {
                case DelegatingFrameSectionsTransitionInfo frameTransition:
                    if (previousFrame.Index > nextFrame.Index)
                    {
                        // If the previous frame is on top of the next one, we hide the previous frame to reveal the next one underneath.

                        // 1.  We must first hide all frames that would be visible between our two target frames.
                        var framesToHideInstantly = _frames.Values
                                                    .Where(f => f.State == FrameState.Shown && f.Index > nextFrame.Index && f.Index < previousFrame.Index);

                        foreach (var f in framesToHideInstantly)
                        {
                            f.Frame.Visibility = Visibility.Collapsed;
                            f.State            = FrameState.Hidden;
                        }

                        // 2. Animate the previous frame
                        await frameTransition.Run(frameToHide : previousFrame.Frame, frameToShow : nextFrame.Frame, frameToShowIsAboveFrameToHide : false);

                        // 3. Once faded out, collapse the previous frame.
                        previousFrame.Frame.Visibility = Visibility.Collapsed;
                    }
                    else
                    {
                        // Otherwise, the next frame is displayed on top of the previous one.
                        await frameTransition.Run(frameToHide : previousFrame.Frame, frameToShow : nextFrame.Frame, frameToShowIsAboveFrameToHide : true);

                        // 5. Collapse the previous frame that is no longer visible.
                        previousFrame.Frame.Visibility = Visibility.Collapsed;
                    }
                    break;

                case UIViewControllerSectionsTransitionInfo viewControllerTransitionInfo:
                    throw new InvalidOperationException($"UIViewControllerTransitionInfo is only supported for modal operations.");

                default:
                    throw new InvalidOperationException($"Unsupported transition info type '{transitionInfo.GetType()}'.");
                }
            }
        }