From 036713c6699397478c44da912f135a15505b46b4 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 10 Mar 2026 11:48:55 +0800 Subject: [PATCH] Refactor UI thread invocation with DispatcherHelper Introduce DispatcherHelper for safe UI thread access and replace direct Dispatcher.Invoke calls across the codebase. This centralizes thread invocation logic, reduces boilerplate, and improves maintainability. Some methods are refactored for clarity and UI thread safety. --- .../Plugin/JsonRPCPluginSettings.cs | 9 +- .../Resource/DispatcherHelper.cs | 101 ++++++++++++++++++ Flow.Launcher.Core/Resource/Theme.cs | 4 +- Flow.Launcher/App.xaml.cs | 6 +- Flow.Launcher/Helper/SingleInstance.cs | 5 +- .../Helper/WallpaperPathRetrieval.cs | 10 +- Flow.Launcher/MainWindow.xaml.cs | 23 ++-- Flow.Launcher/MessageBoxEx.xaml.cs | 14 ++- Flow.Launcher/Msg.xaml.cs | 5 +- Flow.Launcher/MsgWithButton.xaml.cs | 5 +- Flow.Launcher/Notification.cs | 6 +- Flow.Launcher/ProgressBoxEx.xaml.cs | 37 ++----- Flow.Launcher/PublicAPIInstance.cs | 4 +- Flow.Launcher/ReleaseNotesWindow.xaml.cs | 5 +- .../SettingsPanePluginStoreViewModel.cs | 3 +- Flow.Launcher/ViewModel/MainViewModel.cs | 31 +++--- 16 files changed, 177 insertions(+), 91 deletions(-) create mode 100644 Flow.Launcher.Core/Resource/DispatcherHelper.cs diff --git a/Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs b/Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs index abefd47bc..ac36a02ae 100644 --- a/Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs +++ b/Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; +using Flow.Launcher.Core.Resource; using Flow.Launcher.Infrastructure.Storage; using Flow.Launcher.Plugin; @@ -99,14 +100,14 @@ namespace Flow.Launcher.Core.Plugin { case TextBox textBox: var text = value as string ?? string.Empty; - textBox.Dispatcher.Invoke(() => textBox.Text = text); + DispatcherHelper.Invoke(() => textBox.Text = text); break; case PasswordBox passwordBox: var password = value as string ?? string.Empty; - passwordBox.Dispatcher.Invoke(() => passwordBox.Password = password); + DispatcherHelper.Invoke(() => passwordBox.Password = password); break; case ComboBox comboBox: - comboBox.Dispatcher.Invoke(() => comboBox.SelectedItem = value); + DispatcherHelper.Invoke(() => comboBox.SelectedItem = value); break; case CheckBox checkBox: var isChecked = value is bool boolValue @@ -114,7 +115,7 @@ namespace Flow.Launcher.Core.Plugin // If can parse the default value to bool, use it, otherwise use false : value is string stringValue && bool.TryParse(stringValue, out var boolValueFromString) && boolValueFromString; - checkBox.Dispatcher.Invoke(() => checkBox.IsChecked = isChecked); + DispatcherHelper.Invoke(() => checkBox.IsChecked = isChecked); break; } } diff --git a/Flow.Launcher.Core/Resource/DispatcherHelper.cs b/Flow.Launcher.Core/Resource/DispatcherHelper.cs new file mode 100644 index 000000000..5368d7677 --- /dev/null +++ b/Flow.Launcher.Core/Resource/DispatcherHelper.cs @@ -0,0 +1,101 @@ +using System; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Threading; + +namespace Flow.Launcher.Core.Resource; + +#pragma warning disable VSTHRD001 // Avoid legacy thread switching APIs + +public static class DispatcherHelper +{ + public static void Invoke(Action action, DispatcherPriority priority = DispatcherPriority.Normal) + { + Invoke(Application.Current?.Dispatcher, action, priority); + } + + public static T Invoke(Func func, DispatcherPriority priority = DispatcherPriority.Normal) + { + return Invoke(Application.Current?.Dispatcher, func, priority); + } + + public static void Invoke(Dispatcher dispatcher, Action action, DispatcherPriority priority = DispatcherPriority.Normal) + { + if (dispatcher == null) return; + if (dispatcher.CheckAccess()) + { + action(); + } + else + { + dispatcher.Invoke(action, priority); + } + } + + public static T Invoke(Dispatcher dispatcher, Func func, DispatcherPriority priority = DispatcherPriority.Normal) + { + if (dispatcher == null) return default; + if (dispatcher.CheckAccess()) + { + return func(); + } + else + { + return dispatcher.Invoke(func, priority); + } + } + + public static async Task InvokeAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal) + { + await InvokeAsync(Application.Current?.Dispatcher, action, priority); + } + + public static async Task InvokeAsync(Func func, DispatcherPriority priority = DispatcherPriority.Normal) + { + return await InvokeAsync(Application.Current?.Dispatcher, func, priority); + } + + public static async Task InvokeAsync(Func func, DispatcherPriority priority = DispatcherPriority.Normal) + { + await InvokeAsync(Application.Current?.Dispatcher, func, priority); + } + + public static async Task InvokeAsync(Dispatcher dispatcher, Action action, DispatcherPriority priority = DispatcherPriority.Normal) + { + if (dispatcher == null) return; + if (dispatcher.CheckAccess()) + { + action(); + } + else + { + await dispatcher.InvokeAsync(action, priority); + } + } + + public static async Task InvokeAsync(Dispatcher dispatcher, Func func, DispatcherPriority priority = DispatcherPriority.Normal) + { + if (dispatcher == null) return default; + if (dispatcher.CheckAccess()) + { + return func(); + } + else + { + return await dispatcher.InvokeAsync(func, priority); + } + } + + public static async Task InvokeAsync(Dispatcher dispatcher, Func func, DispatcherPriority priority = DispatcherPriority.Normal) + { + if (dispatcher == null) return; + if (dispatcher.CheckAccess()) + { + await func(); + } + else + { + await dispatcher.InvokeAsync(func, priority); + } + } +} diff --git a/Flow.Launcher.Core/Resource/Theme.cs b/Flow.Launcher.Core/Resource/Theme.cs index fb463b4d4..a5235e376 100644 --- a/Flow.Launcher.Core/Resource/Theme.cs +++ b/Flow.Launcher.Core/Resource/Theme.cs @@ -596,7 +596,7 @@ namespace Flow.Launcher.Core.Resource /// public async Task RefreshFrameAsync() { - await Application.Current.Dispatcher.InvokeAsync(() => + await DispatcherHelper.InvokeAsync(() => { // Get the actual backdrop type and drop shadow effect settings var (backdropType, useDropShadowEffect) = GetActualValue(); @@ -623,7 +623,7 @@ namespace Flow.Launcher.Core.Resource /// public async Task SetBlurForWindowAsync() { - await Application.Current.Dispatcher.InvokeAsync(() => + await DispatcherHelper.InvokeAsync(() => { // Get the actual backdrop type and drop shadow effect settings var (backdropType, _) = GetActualValue(); diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index da11380b8..314a751b0 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -334,7 +334,7 @@ namespace Flow.Launcher var timer = new PeriodicTimer(TimeSpan.FromHours(5)); await PluginInstaller.CheckForPluginUpdatesAsync((plugins) => { - Current.Dispatcher.Invoke(() => + DispatcherHelper.Invoke(() => { var pluginUpdateWindow = new PluginUpdateWindow(plugins); pluginUpdateWindow.ShowDialog(); @@ -345,7 +345,7 @@ namespace Flow.Launcher // check updates on startup await PluginInstaller.CheckForPluginUpdatesAsync((plugins) => { - Current.Dispatcher.Invoke(() => + DispatcherHelper.Invoke(() => { var pluginUpdateWindow = new PluginUpdateWindow(plugins); pluginUpdateWindow.ShowDialog(); @@ -444,7 +444,7 @@ namespace Flow.Launcher { // Dispose needs to be called on the main Windows thread, // since some resources owned by the thread need to be disposed. - _mainWindow?.Dispatcher.Invoke(_mainWindow.Dispose); + DispatcherHelper.Invoke(_mainWindow?.Dispatcher, _mainWindow.Dispose); _mainVM?.Dispose(); DialogJump.Dispose(); _internationalization.Dispose(); diff --git a/Flow.Launcher/Helper/SingleInstance.cs b/Flow.Launcher/Helper/SingleInstance.cs index de2579b62..45d76491d 100644 --- a/Flow.Launcher/Helper/SingleInstance.cs +++ b/Flow.Launcher/Helper/SingleInstance.cs @@ -3,6 +3,7 @@ using System.IO.Pipes; using System.Threading; using System.Threading.Tasks; using System.Windows; +using Flow.Launcher.Core.Resource; // http://blogs.microsoft.co.il/arik/2010/05/28/wpf-single-instance-application/ // modified to allow single instace restart @@ -100,7 +101,9 @@ namespace Flow.Launcher.Helper await pipeServer.WaitForConnectionAsync(); // Do an asynchronous call to ActivateFirstInstance function - Application.Current?.Dispatcher.Invoke(ActivateFirstInstance); +#pragma warning disable VSTHRD103 // Call async methods when in an async method + DispatcherHelper.Invoke(ActivateFirstInstance); +#pragma warning restore VSTHRD103 // Call async methods when in an async method // Disconect client pipeServer.Disconnect(); diff --git a/Flow.Launcher/Helper/WallpaperPathRetrieval.cs b/Flow.Launcher/Helper/WallpaperPathRetrieval.cs index fd04b3e88..92b6d5cdd 100644 --- a/Flow.Launcher/Helper/WallpaperPathRetrieval.cs +++ b/Flow.Launcher/Helper/WallpaperPathRetrieval.cs @@ -3,9 +3,9 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; -using System.Windows; using System.Windows.Media; using System.Windows.Media.Imaging; +using Flow.Launcher.Core.Resource; using Flow.Launcher.Infrastructure; using Microsoft.Win32; @@ -22,11 +22,11 @@ public static class WallpaperPathRetrieval public static Brush GetWallpaperBrush() { // Invoke the method on the UI thread - if (!Application.Current.Dispatcher.CheckAccess()) - { - return Application.Current.Dispatcher.Invoke(GetWallpaperBrush); - } + return DispatcherHelper.Invoke(GetWallpaperBrush1); + } + private static Brush GetWallpaperBrush1() + { try { var wallpaperPath = Win32Helper.GetWallpaperPath(); diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 60517db97..9aa9724a0 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -153,7 +153,7 @@ namespace Flow.Launcher Localize.appUpdateButtonContent(), () => { - Application.Current.Dispatcher.Invoke(() => + DispatcherHelper.Invoke(() => { var releaseNotesWindow = new ReleaseNotesWindow(); releaseNotesWindow.Show(); @@ -225,7 +225,7 @@ namespace Flow.Launcher { case nameof(MainViewModel.MainWindowVisibilityStatus): { - Dispatcher.Invoke(() => + DispatcherHelper.Invoke(() => { if (_viewModel.MainWindowVisibilityStatus) { @@ -269,7 +269,7 @@ namespace Flow.Launcher { // QueryTextBox seems to be update with a DispatcherPriority as low as ContextIdle. // To ensure QueryTextBox is up to date with QueryText from the View, we need to Dispatch with such a priority - Dispatcher.Invoke(() => QueryTextBox.CaretIndex = QueryTextBox.Text.Length); + DispatcherHelper.Invoke(() => QueryTextBox.CaretIndex = QueryTextBox.Text.Length); _viewModel.QueryTextCursorMovedToEnd = false; } break; @@ -542,7 +542,7 @@ namespace Flow.Launcher // Switch to Normal state WindowState = WindowState.Normal; - Application.Current?.Dispatcher.Invoke(new Action(() => + DispatcherHelper.Invoke(() => { double normalWidth = Width; double normalHeight = Height; @@ -555,7 +555,7 @@ namespace Flow.Launcher { DragMove(); } - }), DispatcherPriority.ApplicationIdle); + }, DispatcherPriority.ApplicationIdle); } else { @@ -726,19 +726,8 @@ namespace Flow.Launcher { Win32Helper.RegisterSleepModeListener(() => { - if (Application.Current == null) - { - return; - } - // We must run InitSoundEffects on UI thread because MediaPlayer is a DispatcherObject - if (!Application.Current.Dispatcher.CheckAccess()) - { - Application.Current.Dispatcher.Invoke(InitSoundEffects); - return; - } - - InitSoundEffects(); + DispatcherHelper.Invoke(InitSoundEffects); }); } catch (Exception e) diff --git a/Flow.Launcher/MessageBoxEx.xaml.cs b/Flow.Launcher/MessageBoxEx.xaml.cs index 907bfb926..469733357 100644 --- a/Flow.Launcher/MessageBoxEx.xaml.cs +++ b/Flow.Launcher/MessageBoxEx.xaml.cs @@ -3,6 +3,7 @@ using System.IO; using System.Threading.Tasks; using System.Windows; using System.Windows.Input; +using Flow.Launcher.Core.Resource; using Flow.Launcher.Infrastructure; namespace Flow.Launcher @@ -29,11 +30,16 @@ namespace Flow.Launcher MessageBoxImage icon = MessageBoxImage.None, MessageBoxResult defaultResult = MessageBoxResult.OK) { - if (!Application.Current.Dispatcher.CheckAccess()) - { - return Application.Current.Dispatcher.Invoke(() => Show(messageBoxText, caption, button, icon, defaultResult)); - } + return DispatcherHelper.Invoke(() => Show1(messageBoxText, caption, button, icon, defaultResult)); + } + private static MessageBoxResult Show1( + string messageBoxText, + string caption = "", + MessageBoxButton button = MessageBoxButton.OK, + MessageBoxImage icon = MessageBoxImage.None, + MessageBoxResult defaultResult = MessageBoxResult.OK) + { try { msgBox = new MessageBoxEx(button); diff --git a/Flow.Launcher/Msg.xaml.cs b/Flow.Launcher/Msg.xaml.cs index dd7d4495c..5e47d01a1 100644 --- a/Flow.Launcher/Msg.xaml.cs +++ b/Flow.Launcher/Msg.xaml.cs @@ -3,6 +3,7 @@ using System.IO; using System.Windows; using System.Windows.Input; using System.Windows.Media.Animation; +using Flow.Launcher.Core.Resource; using Flow.Launcher.Infrastructure; using Flow.Launcher.Plugin.SharedModels; @@ -80,12 +81,12 @@ namespace Flow.Launcher Show(); - await Dispatcher.InvokeAsync(async () => + await DispatcherHelper.InvokeAsync(async () => { if (!closing) { closing = true; - await Dispatcher.InvokeAsync(fadeOutStoryboard.Begin); + fadeOutStoryboard.Begin(); } }); } diff --git a/Flow.Launcher/MsgWithButton.xaml.cs b/Flow.Launcher/MsgWithButton.xaml.cs index 7ae53e6c5..8ee95bc57 100644 --- a/Flow.Launcher/MsgWithButton.xaml.cs +++ b/Flow.Launcher/MsgWithButton.xaml.cs @@ -3,6 +3,7 @@ using System.IO; using System.Windows; using System.Windows.Input; using System.Windows.Media.Animation; +using Flow.Launcher.Core.Resource; using Flow.Launcher.Infrastructure; using Flow.Launcher.Plugin.SharedModels; @@ -82,12 +83,12 @@ namespace Flow.Launcher Show(); - await Dispatcher.InvokeAsync(async () => + await DispatcherHelper.InvokeAsync(async () => { if (!closing) { closing = true; - await Dispatcher.InvokeAsync(fadeOutStoryboard.Begin); + fadeOutStoryboard.Begin(); } }); } diff --git a/Flow.Launcher/Notification.cs b/Flow.Launcher/Notification.cs index deb5442a4..aeac09579 100644 --- a/Flow.Launcher/Notification.cs +++ b/Flow.Launcher/Notification.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Concurrent; using System.IO; -using System.Windows; +using Flow.Launcher.Core.Resource; using Flow.Launcher.Infrastructure; using Microsoft.Toolkit.Uwp.Notifications; @@ -41,7 +41,7 @@ namespace Flow.Launcher public static void Show(string title, string subTitle, string iconPath = null) { - Application.Current.Dispatcher.Invoke(() => + DispatcherHelper.Invoke(() => { ShowInternal(title, subTitle, iconPath); }); @@ -91,7 +91,7 @@ namespace Flow.Launcher public static void ShowWithButton(string title, string buttonText, Action buttonAction, string subTitle, string iconPath = null) { - Application.Current.Dispatcher.Invoke(() => + DispatcherHelper.Invoke(() => { ShowInternalWithButton(title, buttonText, buttonAction, subTitle, iconPath); }); diff --git a/Flow.Launcher/ProgressBoxEx.xaml.cs b/Flow.Launcher/ProgressBoxEx.xaml.cs index 119463348..7874f118e 100644 --- a/Flow.Launcher/ProgressBoxEx.xaml.cs +++ b/Flow.Launcher/ProgressBoxEx.xaml.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using System.Windows; using System.Windows.Input; +using Flow.Launcher.Core.Resource; namespace Flow.Launcher { @@ -22,19 +23,7 @@ namespace Flow.Launcher ProgressBoxEx progressBox = null; try { - if (!Application.Current.Dispatcher.CheckAccess()) - { - await Application.Current.Dispatcher.InvokeAsync(() => - { - progressBox = new ProgressBoxEx(cancelProgress) - { - Title = caption - }; - progressBox.TitleTextBlock.Text = caption; - progressBox.Show(); - }); - } - else + await DispatcherHelper.InvokeAsync(() => { progressBox = new ProgressBoxEx(cancelProgress) { @@ -42,7 +31,7 @@ namespace Flow.Launcher }; progressBox.TitleTextBlock.Text = caption; progressBox.Show(); - } + }); await reportProgressAsync(progressBox.ReportProgress).ConfigureAwait(false); } @@ -54,28 +43,20 @@ namespace Flow.Launcher } finally { - if (!Application.Current.Dispatcher.CheckAccess()) - { - await Application.Current.Dispatcher.InvokeAsync(() => - { - progressBox?.Close(); - }); - } - else + await DispatcherHelper.InvokeAsync(() => { progressBox?.Close(); - } + }); } } private void ReportProgress(double progress) { - if (!Application.Current.Dispatcher.CheckAccess()) - { - Application.Current.Dispatcher.Invoke(() => ReportProgress(progress)); - return; - } + DispatcherHelper.Invoke(() => ReportProgress1(progress)); + } + private void ReportProgress1(double progress) + { if (progress < 0) { ProgressBar.Value = 0; diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index 55737151a..c7dec1d19 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Specialized; @@ -141,7 +141,7 @@ namespace Flow.Launcher public void OpenSettingDialog() { - Application.Current.Dispatcher.Invoke(() => + DispatcherHelper.Invoke(() => { SettingWindow sw = SingletonWindowOpener.Open(); }); diff --git a/Flow.Launcher/ReleaseNotesWindow.xaml.cs b/Flow.Launcher/ReleaseNotesWindow.xaml.cs index 12e0aa1d8..5d5f73aba 100644 --- a/Flow.Launcher/ReleaseNotesWindow.xaml.cs +++ b/Flow.Launcher/ReleaseNotesWindow.xaml.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using System.Windows; using System.Windows.Input; using System.Windows.Media; +using Flow.Launcher.Core.Resource; using Flow.Launcher.Infrastructure.Http; using iNKORE.UI.WPF.Modern; @@ -28,7 +29,7 @@ namespace Flow.Launcher private void ThemeManager_ActualApplicationThemeChanged(ThemeManager sender, object args) { - Application.Current.Dispatcher.Invoke(() => + DispatcherHelper.Invoke(() => { if (ThemeManager.Current.ActualApplicationTheme == ApplicationTheme.Light) { @@ -124,7 +125,7 @@ namespace Flow.Launcher { var output = await GetReleaseNotesMarkdownAsync().ConfigureAwait(false); - Application.Current.Dispatcher.Invoke(() => + DispatcherHelper.Invoke(() => { RefreshProgressRing.Visibility = Visibility.Collapsed; if (string.IsNullOrEmpty(output)) diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs index d67695a75..539711452 100644 --- a/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs +++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using System.Windows; using CommunityToolkit.Mvvm.Input; using Flow.Launcher.Core.Plugin; +using Flow.Launcher.Core.Resource; using Flow.Launcher.Plugin; using Flow.Launcher.ViewModel; @@ -115,7 +116,7 @@ public partial class SettingsPanePluginStoreViewModel : BaseModel { await PluginInstaller.CheckForPluginUpdatesAsync((plugins) => { - Application.Current.Dispatcher.Invoke(() => + DispatcherHelper.Invoke(() => { var pluginUpdateWindow = new PluginUpdateWindow(plugins); pluginUpdateWindow.ShowDialog(); diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 333ac3652..6dd27bca5 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -16,6 +16,7 @@ using System.Windows.Threading; using CommunityToolkit.Mvvm.DependencyInjection; using CommunityToolkit.Mvvm.Input; using Flow.Launcher.Core.Plugin; +using Flow.Launcher.Core.Resource; using Flow.Launcher.Helper; using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.DialogJump; @@ -763,12 +764,11 @@ namespace Flow.Launcher.ViewModel public void ChangeQueryText(string queryText, bool isReQuery = false) { // Must check access so that we will not block the UI thread which causes window visibility issue - if (!Application.Current.Dispatcher.CheckAccess()) - { - Application.Current.Dispatcher.Invoke(() => ChangeQueryText(queryText, isReQuery)); - return; - } + DispatcherHelper.Invoke(() => ChangeQueryText1(queryText, isReQuery)); + } + private void ChangeQueryText1(string queryText, bool isReQuery = false) + { if (QueryText != queryText) { // Change query text first @@ -795,12 +795,11 @@ namespace Flow.Launcher.ViewModel private async Task ChangeQueryTextAsync(string queryText, bool isReQuery = false) { // Must check access so that we will not block the UI thread which causes window visibility issue - if (!Application.Current.Dispatcher.CheckAccess()) - { - await Application.Current.Dispatcher.InvokeAsync(() => ChangeQueryTextAsync(queryText, isReQuery)); - return; - } + await DispatcherHelper.InvokeAsync(() => ChangeQueryText1Async(queryText, isReQuery)); + } + private async Task ChangeQueryText1Async(string queryText, bool isReQuery = false) + { if (QueryText != queryText) { // Change query text first @@ -1951,10 +1950,12 @@ namespace Flow.Launcher.ViewModel if (dialogWindowHandleChanged) { // Only update the position - Application.Current?.Dispatcher.Invoke(() => +#pragma warning disable VSTHRD103 // Call async methods when in an async method + DispatcherHelper.Invoke(() => { (Application.Current?.MainWindow as MainWindow)?.UpdatePosition(); }); +#pragma warning restore VSTHRD103 // Call async methods when in an async method _ = ResetWindowAsync(); } @@ -2049,7 +2050,7 @@ namespace Flow.Launcher.ViewModel if (_previousMainWindowVisibilityStatus) { // Only update the position - Application.Current?.Dispatcher.Invoke(() => + DispatcherHelper.Invoke(() => { (Application.Current?.MainWindow as MainWindow)?.UpdatePosition(); }); @@ -2112,7 +2113,7 @@ namespace Flow.Launcher.ViewModel if (App.LoadingOrExiting) return; // When application is exiting, the Application.Current will be null - Application.Current?.Dispatcher.Invoke(() => + DispatcherHelper.Invoke(() => { // When application is exiting, the Application.Current will be null if (Application.Current?.MainWindow is MainWindow mainWindow) @@ -2194,7 +2195,7 @@ namespace Flow.Launcher.ViewModel } // When application is exiting, the Application.Current will be null - Application.Current?.Dispatcher.Invoke(() => + DispatcherHelper.Invoke(() => { // When application is exiting, the Application.Current will be null if (Application.Current?.MainWindow is MainWindow mainWindow) @@ -2328,7 +2329,7 @@ namespace Flow.Launcher.ViewModel public void FocusQueryTextBox() { // When application is exiting, the Application.Current will be null - Application.Current?.Dispatcher.Invoke(() => + DispatcherHelper.Invoke(() => { // When application is exiting, the Application.Current will be null if (Application.Current?.MainWindow is MainWindow window)