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;