using System; using System.Windows; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Threading; namespace 自救器呼吸器综合检验仪 { internal static class WindowNavigationHelper { private const string SlideTransformResourceKey = "__WindowNavigationHelperSlideTransform"; private static readonly TimeSpan TargetFadeDuration = TimeSpan.FromMilliseconds(420); private static readonly TimeSpan ContentSlideDuration = TimeSpan.FromMilliseconds(360); private static readonly CubicEase SlideEase = new CubicEase { EasingMode = EasingMode.EaseOut }; public static void ShowWithoutWhiteFlash(Window currentWindow, Window targetWindow, string loadingTitle = null, string loadingSubtitle = null) { if (!CanInteractWith(currentWindow) || !CanInteractWith(targetWindow)) { return; } ApplyWindowPlacement(currentWindow, targetWindow); PrepareTargetWindowForReveal(targetWindow); if (targetWindow.IsVisible) { RevealTargetWindow(currentWindow, targetWindow, null); return; } LoadingOverlayWindow loadingOverlay = ShowLoadingOverlay(currentWindow, loadingTitle, loadingSubtitle); if (targetWindow.IsLoaded) { targetWindow.Show(); targetWindow.Dispatcher.BeginInvoke( DispatcherPriority.ContextIdle, new Action(() => RevealTargetWindow(currentWindow, targetWindow, loadingOverlay))); return; } EventHandler contentRenderedHandler = null; contentRenderedHandler = (sender, args) => { targetWindow.ContentRendered -= contentRenderedHandler; RevealTargetWindow(currentWindow, targetWindow, loadingOverlay); }; targetWindow.ContentRendered += contentRenderedHandler; targetWindow.Show(); } public static void RestoreWindow(Window windowToRestore, Action beforeRestore = null) { if (!CanInteractWith(windowToRestore)) { return; } beforeRestore?.Invoke(); if (!windowToRestore.IsVisible) { windowToRestore.Show(); } windowToRestore.Activate(); } private static void ApplyWindowPlacement(Window currentWindow, Window targetWindow) { targetWindow.WindowStartupLocation = WindowStartupLocation.Manual; targetWindow.WindowState = currentWindow.WindowState; if (currentWindow.WindowState != WindowState.Normal) { return; } targetWindow.Left = currentWindow.Left; targetWindow.Top = currentWindow.Top; targetWindow.Width = currentWindow.ActualWidth > 0 ? currentWindow.ActualWidth : currentWindow.Width; targetWindow.Height = currentWindow.ActualHeight > 0 ? currentWindow.ActualHeight : currentWindow.Height; } private static void PrepareTargetWindowForReveal(Window targetWindow) { targetWindow.Opacity = 0; FrameworkElement contentRoot = targetWindow.Content as FrameworkElement; if (contentRoot == null) { return; } TranslateTransform slideTransform = GetOrCreateSlideTransform(contentRoot); slideTransform.X = 72; contentRoot.Opacity = 0.9; } private static void RevealTargetWindow(Window currentWindow, Window targetWindow, LoadingOverlayWindow loadingOverlay) { if (!CanInteractWith(currentWindow) || !CanInteractWith(targetWindow)) { CloseLoadingOverlay(loadingOverlay); return; } currentWindow.Hide(); AnimateTargetWindow(targetWindow); targetWindow.Activate(); targetWindow.Dispatcher.BeginInvoke( DispatcherPriority.ContextIdle, new Action(() => CloseLoadingOverlay(loadingOverlay))); } private static LoadingOverlayWindow ShowLoadingOverlay(Window currentWindow, string loadingTitle, string loadingSubtitle) { if (!CanInteractWith(currentWindow)) { return null; } LoadingOverlayWindow loadingOverlay = new LoadingOverlayWindow(); loadingOverlay.AlignTo(currentWindow); loadingOverlay.MatchTopmost(currentWindow); loadingOverlay.SetMessage( loadingTitle ?? "正在切换检测页面", loadingSubtitle ?? "正在加载页面资源和设备状态,请稍候..."); loadingOverlay.Show(); return loadingOverlay; } private static void CloseLoadingOverlay(LoadingOverlayWindow loadingOverlay) { if (loadingOverlay == null) { return; } if (loadingOverlay.Dispatcher.HasShutdownStarted || loadingOverlay.Dispatcher.HasShutdownFinished) { return; } if (!loadingOverlay.IsLoaded) { return; } loadingOverlay.CloseWhenReady(); } private static void AnimateTargetWindow(Window targetWindow) { if (targetWindow == null || targetWindow.Dispatcher.HasShutdownStarted || targetWindow.Dispatcher.HasShutdownFinished) { return; } DoubleAnimation fadeInAnimation = new DoubleAnimation { From = targetWindow.Opacity, To = 1, Duration = new Duration(TargetFadeDuration), FillBehavior = FillBehavior.HoldEnd }; targetWindow.BeginAnimation(UIElement.OpacityProperty, fadeInAnimation); FrameworkElement contentRoot = targetWindow.Content as FrameworkElement; if (contentRoot == null) { return; } TranslateTransform slideTransform = GetOrCreateSlideTransform(contentRoot); DoubleAnimation slideAnimation = new DoubleAnimation { From = slideTransform.X, To = 0, Duration = new Duration(ContentSlideDuration), EasingFunction = SlideEase, FillBehavior = FillBehavior.HoldEnd }; slideTransform.BeginAnimation(TranslateTransform.XProperty, slideAnimation); DoubleAnimation contentFadeAnimation = new DoubleAnimation { From = contentRoot.Opacity, To = 1, Duration = new Duration(ContentSlideDuration), EasingFunction = SlideEase, FillBehavior = FillBehavior.HoldEnd }; contentRoot.BeginAnimation(UIElement.OpacityProperty, contentFadeAnimation); } private static TranslateTransform GetOrCreateSlideTransform(FrameworkElement contentRoot) { if (contentRoot.Resources[SlideTransformResourceKey] is TranslateTransform cachedTransform) { return cachedTransform; } TranslateTransform slideTransform = null; Transform renderTransform = contentRoot.RenderTransform; if (renderTransform is TranslateTransform existingTranslate) { slideTransform = existingTranslate; } else if (renderTransform is TransformGroup existingGroup) { foreach (Transform child in existingGroup.Children) { if (child is TranslateTransform childTranslate) { slideTransform = childTranslate; break; } } if (slideTransform == null) { slideTransform = new TranslateTransform(); existingGroup.Children.Add(slideTransform); } } else if (renderTransform == null || renderTransform == Transform.Identity || renderTransform.Value.IsIdentity) { slideTransform = new TranslateTransform(); contentRoot.RenderTransform = slideTransform; } else { TransformGroup transformGroup = new TransformGroup(); transformGroup.Children.Add(renderTransform); slideTransform = new TranslateTransform(); transformGroup.Children.Add(slideTransform); contentRoot.RenderTransform = transformGroup; } contentRoot.RenderTransformOrigin = new Point(0.5, 0.5); contentRoot.Resources[SlideTransformResourceKey] = slideTransform; return slideTransform; } private static bool CanInteractWith(Window window) { return window != null && !AppShutdownCoordinator.IsShutdownInProgress && !window.Dispatcher.HasShutdownStarted && !window.Dispatcher.HasShutdownFinished; } } }