更新
This commit is contained in:
257
WindowNavigationHelper.cs
Normal file
257
WindowNavigationHelper.cs
Normal file
@@ -0,0 +1,257 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user