From 07eee51a8bc5263616734886868c2f5328d955be Mon Sep 17 00:00:00 2001 From: Niels Laute Date: Fri, 15 May 2026 11:43:47 +0200 Subject: [PATCH] Settings: speed up page navigation, fix Advanced Paste double-load - Enable NavigationCacheMode.Enabled in NavigablePage so pages inheriting it are kept warm by the Frame; re-navigation no longer rebuilds the XAML tree, ViewModel, file watchers and IPC handlers each time. - Drop EntranceThemeTransition from SettingsCardsAnimations. It replayed on every nav and produced a visible cards-in animation on top of an already slow construction. RepositionThemeTransition is preserved so SettingsExpander expand/collapse stays smooth. - AdvancedPastePage: stop calling UpdatePasteAIUIVisibility() and UpdateFoundryLocalUIAsync() in the Loaded handler. They only affect controls inside the (hidden) provider configuration dialog, and the Add/Edit handlers already call them right before ShowAsync. Removing the duplicate work eliminates the visible second reflow (the 'double load') and avoids an unnecessary Foundry Local process probe on every nav. - Guard RefreshEnabledState so dialog-only updates only run while the provider configuration dialog is actually open, preventing duplicate work on IPC general-settings broadcasts. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Settings.UI/Helpers/NavigablePage.cs | 5 ++++ .../Settings.UI/SettingsXAML/App.xaml | 3 +-- .../Views/AdvancedPastePage.xaml.cs | 26 +++++++++++++++---- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/settings-ui/Settings.UI/Helpers/NavigablePage.cs b/src/settings-ui/Settings.UI/Helpers/NavigablePage.cs index 51c89875abe2..f07512429b9e 100644 --- a/src/settings-ui/Settings.UI/Helpers/NavigablePage.cs +++ b/src/settings-ui/Settings.UI/Helpers/NavigablePage.cs @@ -10,6 +10,7 @@ using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Hosting; using Microsoft.UI.Xaml.Media; +using Microsoft.UI.Xaml.Navigation; using Windows.UI; namespace Microsoft.PowerToys.Settings.UI.Helpers; @@ -23,6 +24,10 @@ public abstract partial class NavigablePage : Page public NavigablePage() { + // Cache the page instance so re-navigating doesn't rebuild the XAML tree, ViewModel, + // file watchers and IPC handlers each time. The Frame's default CacheSize (10) is + // sufficient to keep all top-level settings pages warm. + NavigationCacheMode = NavigationCacheMode.Enabled; Loaded += OnPageLoaded; } diff --git a/src/settings-ui/Settings.UI/SettingsXAML/App.xaml b/src/settings-ui/Settings.UI/SettingsXAML/App.xaml index d99fb6d7b301..49563903ffef 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/App.xaml +++ b/src/settings-ui/Settings.UI/SettingsXAML/App.xaml @@ -90,10 +90,9 @@ - - + diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Views/AdvancedPastePage.xaml.cs b/src/settings-ui/Settings.UI/SettingsXAML/Views/AdvancedPastePage.xaml.cs index 8cae5dbd5f0b..ddb0d0a51bd3 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/Views/AdvancedPastePage.xaml.cs +++ b/src/settings-ui/Settings.UI/SettingsXAML/Views/AdvancedPastePage.xaml.cs @@ -30,6 +30,7 @@ public sealed partial class AdvancedPastePage : NavigablePage, IRefreshablePage, private CancellationTokenSource _foundryModelLoadCts; private bool _suppressFoundrySelectionChanged; private bool _isFoundryLocalAvailable; + private bool _isPasteAIProviderDialogOpen; private bool _disposed; private const string PasteAiDialogDefaultTitle = "Paste with AI provider configuration"; @@ -60,11 +61,16 @@ public AdvancedPastePage() FoundryLocalPicker.LoadRequested += FoundryLocalPicker_LoadRequested; } - Loaded += async (s, e) => + Loaded += (s, e) => { ViewModel.OnPageLoaded(); - UpdatePasteAIUIVisibility(); - await UpdateFoundryLocalUIAsync(); + + // Note: UpdatePasteAIUIVisibility() and UpdateFoundryLocalUIAsync() are deliberately + // NOT called here. They only affect controls inside PasteAIProviderConfigurationDialog, + // which is hidden until the user clicks Add/Edit provider. Both Add/Edit handlers call + // them right before ShowAsync(), so running them on every navigation is wasted work + // that produced a visible second reflow ("double load") and, for FoundryLocal, an + // unnecessary process probe. }; Unloaded += (_, _) => @@ -81,8 +87,15 @@ public AdvancedPastePage() public void RefreshEnabledState() { ViewModel.RefreshEnabledState(); - UpdatePasteAIUIVisibility(); - _ = UpdateFoundryLocalUIAsync(); + + // Only refresh the provider-configuration dialog state if it is currently open; + // otherwise this is wasted work (and, for FoundryLocal, an unnecessary process probe) + // that fires every time the runner broadcasts a general-settings update. + if (_isPasteAIProviderDialogOpen) + { + UpdatePasteAIUIVisibility(); + _ = UpdateFoundryLocalUIAsync(); + } } private void EnableAdvancedPasteAI() => ViewModel.EnableAI(); @@ -1116,6 +1129,7 @@ private async void ProviderMenuFlyoutItem_Click(object sender, RoutedEventArgs e RefreshDialogBindings(); PasteAIApiKeyPasswordBox.Password = string.Empty; + _isPasteAIProviderDialogOpen = true; await PasteAIProviderConfigurationDialog.ShowAsync(); } @@ -1143,6 +1157,7 @@ private async void EditPasteAIProviderButton_Click(object sender, RoutedEventArg await UpdateFoundryLocalUIAsync(); RefreshDialogBindings(); PasteAIApiKeyPasswordBox.Password = ViewModel.GetPasteAIApiKey(provider.Id, provider.ServiceType); + _isPasteAIProviderDialogOpen = true; await PasteAIProviderConfigurationDialog.ShowAsync(); } @@ -1159,6 +1174,7 @@ private void RemovePasteAIProviderButton_Click(object sender, RoutedEventArgs e) private void PasteAIProviderConfigurationDialog_Closed(ContentDialog sender, ContentDialogClosedEventArgs args) { + _isPasteAIProviderDialogOpen = false; ViewModel?.CancelPasteAIProviderDraft(); PasteAIProviderConfigurationDialog.Title = PasteAiDialogDefaultTitle; PasteAIApiKeyPasswordBox.Password = string.Empty;