258 lines
9.3 KiB
C#
258 lines
9.3 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|