diff --git a/Ink Canvas/MainWindow_cs/MW_TrayIcon.cs b/Ink Canvas/MainWindow_cs/MW_TrayIcon.cs index 41e539d7..f266aec0 100644 --- a/Ink Canvas/MainWindow_cs/MW_TrayIcon.cs +++ b/Ink Canvas/MainWindow_cs/MW_TrayIcon.cs @@ -87,7 +87,7 @@ namespace Ink_Canvas private void SysTrayMenu_Closed(object sender, RoutedEventArgs e) { var mainWin = (MainWindow)Current.MainWindow; - if (mainWin.IsLoaded) + if (mainWin != null && mainWin.IsLoaded) { // 菜单关闭后,恢复主窗口的置顶状态 if (Ink_Canvas.MainWindow.Settings.Advanced.IsAlwaysOnTop && Ink_Canvas.MainWindow.Settings.Advanced.IsNoFocusMode) @@ -112,7 +112,7 @@ namespace Ink_Canvas private void CloseAppTrayIconMenuItem_Clicked(object sender, RoutedEventArgs e) { var mainWin = (MainWindow)Current.MainWindow; - if (mainWin.IsLoaded) + if (mainWin != null && mainWin.IsLoaded) { IsAppExitByUser = true; mainWin.BtnExit_Click(null, null); @@ -136,7 +136,7 @@ namespace Ink_Canvas private void RestartAppTrayIconMenuItem_Clicked(object sender, RoutedEventArgs e) { var mainWin = (MainWindow)Current.MainWindow; - if (mainWin.IsLoaded) + if (mainWin != null && mainWin.IsLoaded) { IsAppExitByUser = true; @@ -176,7 +176,7 @@ namespace Ink_Canvas private void ForceFullScreenTrayIconMenuItem_Clicked(object sender, RoutedEventArgs e) { var mainWin = (MainWindow)Current.MainWindow; - if (mainWin.IsLoaded) + if (mainWin != null && mainWin.IsLoaded) { Ink_Canvas.MainWindow.MoveWindow(new WindowInteropHelper(mainWin).Handle, 0, 0, Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, true); @@ -199,7 +199,7 @@ namespace Ink_Canvas private void FoldFloatingBarTrayIconMenuItem_Clicked(object sender, RoutedEventArgs e) { var mainWin = (MainWindow)Current.MainWindow; - if (mainWin.IsLoaded) + if (mainWin != null && mainWin.IsLoaded) if (mainWin.isFloatingBarFolded) mainWin.UnFoldFloatingBar_MouseUp(new object(), null); else mainWin.FoldFloatingBar_MouseUp(new object(), null); } @@ -221,7 +221,7 @@ namespace Ink_Canvas private void ResetFloatingBarPositionTrayIconMenuItem_Clicked(object sender, RoutedEventArgs e) { var mainWin = (MainWindow)Current.MainWindow; - if (mainWin.IsLoaded) + if (mainWin != null && mainWin.IsLoaded) { var isInPPTPresentationMode = false; Dispatcher.Invoke(() => @@ -257,19 +257,22 @@ namespace Ink_Canvas { var mi = (MenuItem)sender; var mainWin = (MainWindow)Current.MainWindow; - if (mainWin.IsLoaded) + if (mainWin != null && mainWin.IsLoaded) { mainWin.Hide(); var s = ((TaskbarIcon)Current.Resources["TaskbarTrayIcon"]).ContextMenu; - var ResetFloatingBarPositionTrayIconMenuItem = (MenuItem)s.Items[s.Items.Count - 4]; - var FoldFloatingBarTrayIconMenuItem = (MenuItem)s.Items[s.Items.Count - 5]; - var ForceFullScreenTrayIconMenuItem = (MenuItem)s.Items[s.Items.Count - 6]; - ResetFloatingBarPositionTrayIconMenuItem.IsEnabled = false; - FoldFloatingBarTrayIconMenuItem.IsEnabled = false; - ForceFullScreenTrayIconMenuItem.IsEnabled = false; - ResetFloatingBarPositionTrayIconMenuItem.Opacity = 0.5; - FoldFloatingBarTrayIconMenuItem.Opacity = 0.5; - ForceFullScreenTrayIconMenuItem.Opacity = 0.5; + if (s != null) + { + var ResetFloatingBarPositionTrayIconMenuItem = (MenuItem)s.Items[s.Items.Count - 4]; + var FoldFloatingBarTrayIconMenuItem = (MenuItem)s.Items[s.Items.Count - 5]; + var ForceFullScreenTrayIconMenuItem = (MenuItem)s.Items[s.Items.Count - 6]; + ResetFloatingBarPositionTrayIconMenuItem.IsEnabled = false; + FoldFloatingBarTrayIconMenuItem.IsEnabled = false; + ForceFullScreenTrayIconMenuItem.IsEnabled = false; + ResetFloatingBarPositionTrayIconMenuItem.Opacity = 0.5; + FoldFloatingBarTrayIconMenuItem.Opacity = 0.5; + ForceFullScreenTrayIconMenuItem.Opacity = 0.5; + } } else { @@ -299,19 +302,22 @@ namespace Ink_Canvas { var mi = (MenuItem)sender; var mainWin = (MainWindow)Current.MainWindow; - if (mainWin.IsLoaded) + if (mainWin != null && mainWin.IsLoaded) { mainWin.Show(); var s = ((TaskbarIcon)Current.Resources["TaskbarTrayIcon"]).ContextMenu; - var ResetFloatingBarPositionTrayIconMenuItem = (MenuItem)s.Items[s.Items.Count - 4]; - var FoldFloatingBarTrayIconMenuItem = (MenuItem)s.Items[s.Items.Count - 5]; - var ForceFullScreenTrayIconMenuItem = (MenuItem)s.Items[s.Items.Count - 6]; - ResetFloatingBarPositionTrayIconMenuItem.IsEnabled = true; - FoldFloatingBarTrayIconMenuItem.IsEnabled = true; - ForceFullScreenTrayIconMenuItem.IsEnabled = true; - ResetFloatingBarPositionTrayIconMenuItem.Opacity = 1; - FoldFloatingBarTrayIconMenuItem.Opacity = 1; - ForceFullScreenTrayIconMenuItem.Opacity = 1; + if (s != null) + { + var ResetFloatingBarPositionTrayIconMenuItem = (MenuItem)s.Items[s.Items.Count - 4]; + var FoldFloatingBarTrayIconMenuItem = (MenuItem)s.Items[s.Items.Count - 5]; + var ForceFullScreenTrayIconMenuItem = (MenuItem)s.Items[s.Items.Count - 6]; + ResetFloatingBarPositionTrayIconMenuItem.IsEnabled = true; + FoldFloatingBarTrayIconMenuItem.IsEnabled = true; + ForceFullScreenTrayIconMenuItem.IsEnabled = true; + ResetFloatingBarPositionTrayIconMenuItem.Opacity = 1; + FoldFloatingBarTrayIconMenuItem.Opacity = 1; + ForceFullScreenTrayIconMenuItem.Opacity = 1; + } } else { @@ -340,7 +346,7 @@ namespace Ink_Canvas private void DisableAllHotkeysMenuItem_Clicked(object sender, RoutedEventArgs e) { var mainWin = (MainWindow)Current.MainWindow; - if (mainWin.IsLoaded) + if (mainWin != null && mainWin.IsLoaded) { try { diff --git a/Ink Canvas/Windows/MinimizedTimerControl.xaml.cs b/Ink Canvas/Windows/MinimizedTimerControl.xaml.cs index 377c76da..940c322a 100644 --- a/Ink Canvas/Windows/MinimizedTimerControl.xaml.cs +++ b/Ink Canvas/Windows/MinimizedTimerControl.xaml.cs @@ -2,6 +2,7 @@ using iNKORE.UI.WPF.Modern; using Microsoft.Win32; using System; using System.Timers; +using System.Windows.Threading; using System.Windows; using System.Windows.Controls; using System.Windows.Input; @@ -17,11 +18,16 @@ namespace Ink_Canvas.Windows { private TimerControl parentControl; private System.Timers.Timer updateTimer; + private readonly Dispatcher uiDispatcher; public MinimizedTimerControl() { InitializeComponent(); + // capture the UI dispatcher early so timer callbacks can use it even when + // Application.Current may become null during shutdown + uiDispatcher = this.Dispatcher; + updateTimer = new System.Timers.Timer(100); updateTimer.Elapsed += UpdateTimer_Elapsed; updateTimer.Start(); @@ -46,18 +52,35 @@ namespace Ink_Canvas.Windows if (updateTimer != null) { - updateTimer.Stop(); - updateTimer.Dispose(); + // 先取消事件订阅,防止在停止/释放后仍有回调被触发 + updateTimer.Elapsed -= UpdateTimer_Elapsed; + try + { + updateTimer.Stop(); + } + catch { } + try + { + updateTimer.Dispose(); + } + catch { } + updateTimer = null; } } private void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e) { // 当主题变化时,重新应用主题 - Application.Current.Dispatcher.Invoke(() => + var dispatcher = uiDispatcher ?? Application.Current?.Dispatcher; + if (dispatcher == null) return; + if (dispatcher.HasShutdownStarted || dispatcher.HasShutdownFinished) return; + + // 使用异步调用,避免在关闭过程中同步等待导致异常 + try { - RefreshTheme(); - }); + dispatcher.InvokeAsync(() => RefreshTheme(), DispatcherPriority.Normal); + } + catch { } } /// @@ -99,26 +122,35 @@ namespace Ink_Canvas.Windows { if (parentControl != null) { - Application.Current.Dispatcher.Invoke(() => + var dispatcher = uiDispatcher ?? Application.Current?.Dispatcher; + if (dispatcher == null) return; + if (dispatcher.HasShutdownStarted || dispatcher.HasShutdownFinished) return; + + // 使用异步派发,避免在 Dispatcher 关闭时同步等待导致 TaskCanceledException + try { - if (this.Visibility != Visibility.Visible) + dispatcher.InvokeAsync(() => { - return; - } - - if (ShouldHide()) - { - this.Visibility = Visibility.Collapsed; - var parent = this.Parent as FrameworkElement; - if (parent != null) + if (this.Visibility != Visibility.Visible) { - parent.Visibility = Visibility.Collapsed; + return; } - return; - } - UpdateTimeDisplay(); - }); + if (ShouldHide()) + { + this.Visibility = Visibility.Collapsed; + var parent = this.Parent as FrameworkElement; + if (parent != null) + { + parent.Visibility = Visibility.Collapsed; + } + return; + } + + UpdateTimeDisplay(); + }, DispatcherPriority.Normal); + } + catch { } } } @@ -214,10 +246,15 @@ namespace Ink_Canvas.Windows private void ParentControl_TimerCompleted(object sender, EventArgs e) { - Application.Current.Dispatcher.Invoke(() => + var dispatcher = uiDispatcher ?? Application.Current?.Dispatcher; + if (dispatcher == null) return; + if (dispatcher.HasShutdownStarted || dispatcher.HasShutdownFinished) return; + + try { - Visibility = Visibility.Collapsed; - }); + dispatcher.InvokeAsync(() => { Visibility = Visibility.Collapsed; }, DispatcherPriority.Normal); + } + catch { } } private void SetDigitDisplay(string pathName, int digit, bool isRed = false) @@ -391,7 +428,7 @@ namespace Ink_Canvas.Windows { try { - var mainWindow = Application.Current.MainWindow as MainWindow; + var mainWindow = Application.Current?.MainWindow as MainWindow; if (mainWindow != null) { var currentModeField = mainWindow.GetType().GetField("currentMode", diff --git a/Ink Canvas/Windows/OobeWindow.xaml b/Ink Canvas/Windows/OobeWindow.xaml index cf1e8bb9..cc3f5ace 100644 --- a/Ink Canvas/Windows/OobeWindow.xaml +++ b/Ink Canvas/Windows/OobeWindow.xaml @@ -5,8 +5,8 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" Title="欢迎使用 InkCanvasForClass" - Height="460" - Width="780" + Height="480" + Width="800" MinHeight="300" MinWidth="400" WindowStartupLocation="CenterScreen" diff --git a/Ink Canvas/Windows/PPTTimeCapsule.xaml.cs b/Ink Canvas/Windows/PPTTimeCapsule.xaml.cs index 53984d7c..8739c334 100644 --- a/Ink Canvas/Windows/PPTTimeCapsule.xaml.cs +++ b/Ink Canvas/Windows/PPTTimeCapsule.xaml.cs @@ -28,6 +28,7 @@ namespace Ink_Canvas.Windows private double originalCapsuleWidth = 0; private string lastCountdownText = ""; // 上次的倒计时文本,用于检测文本变化 private Storyboard currentWidthAnimation; // 当前正在运行的宽度动画 + private volatile bool isDisposed = false; public PPTTimeCapsule() { @@ -72,10 +73,43 @@ namespace Ink_Canvas.Windows /// public void Dispose() { - StopTimeUpdate(); - SystemEvents.UserPreferenceChanged -= SystemEvents_UserPreferenceChanged; - timeUpdateTimer?.Dispose(); - countdownUpdateTimer?.Dispose(); + if (isDisposed) return; + isDisposed = true; + + // 先取消系统事件订阅,防止在释放过程中再次触发 + try + { + SystemEvents.UserPreferenceChanged -= SystemEvents_UserPreferenceChanged; + } + catch { } + + // 停止并释放定时器,确保不再触发回调 + try + { + if (timeUpdateTimer != null) + { + timeUpdateTimer.Elapsed -= TimeUpdateTimer_Elapsed; + try { timeUpdateTimer.Stop(); } catch { } + try { timeUpdateTimer.Dispose(); } catch { } + timeUpdateTimer = null; + } + } + catch { } + + try + { + if (countdownUpdateTimer != null) + { + countdownUpdateTimer.Elapsed -= CountdownUpdateTimer_Elapsed; + try { countdownUpdateTimer.Stop(); } catch { } + try { countdownUpdateTimer.Dispose(); } catch { } + countdownUpdateTimer = null; + } + } + catch { } + + // 停止动画 + try { StopColonBlinkAnimation(); } catch { } } private void InitializeTimers() @@ -91,23 +125,39 @@ namespace Ink_Canvas.Windows private void TimeUpdateTimer_Elapsed(object sender, ElapsedEventArgs e) { - Application.Current.Dispatcher.BeginInvoke(new Action(() => + if (isDisposed) return; + + var dispatcher = this.Dispatcher; + if (dispatcher == null || dispatcher.HasShutdownStarted || dispatcher.HasShutdownFinished) return; + + try { - UpdateTimeDisplay(); - }), DispatcherPriority.Normal); + dispatcher.BeginInvoke(new Action(() => + { + if (isDisposed) return; + UpdateTimeDisplay(); + }), DispatcherPriority.Normal); + } + catch { } } private void CountdownUpdateTimer_Elapsed(object sender, ElapsedEventArgs e) { - Application.Current.Dispatcher.BeginInvoke(new Action(() => - { - if (this.Visibility != Visibility.Visible) - { - return; - } + if (isDisposed) return; - UpdateCountdownDisplay(); - }), DispatcherPriority.Normal); + var dispatcher = this.Dispatcher; + if (dispatcher == null || dispatcher.HasShutdownStarted || dispatcher.HasShutdownFinished) return; + + try + { + dispatcher.BeginInvoke(new Action(() => + { + if (isDisposed) return; + if (this.Visibility != Visibility.Visible) return; + UpdateCountdownDisplay(); + }), DispatcherPriority.Normal); + } + catch { } } private void StartTimeUpdate() @@ -724,10 +774,20 @@ namespace Ink_Canvas.Windows private void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e) { - Application.Current.Dispatcher.BeginInvoke(new Action(() => + if (isDisposed) return; + + var dispatcher = this.Dispatcher; + if (dispatcher == null || dispatcher.HasShutdownStarted || dispatcher.HasShutdownFinished) return; + + try { - ApplyTheme(); - }), DispatcherPriority.Normal); + dispatcher.BeginInvoke(new Action(() => + { + if (isDisposed) return; + ApplyTheme(); + }), DispatcherPriority.Normal); + } + catch { } } private void ApplyTheme()