mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-03 17:56:44 +02:00
[Settings] Implement singleton pattern for ShortcutConflictWindow (#42440)
## Summary Fixes issue where multiple ShortcutConflictWindow instances could be opened simultaneously. The window now follows the same singleton pattern as OobeWindow - only one instance can exist at a time, and attempting to open another brings the existing window to the foreground. ## Changes Implemented singleton management for `ShortcutConflictWindow` following the established pattern used by `OobeWindow`: ### App.xaml.cs - Added static field to store the singleton window instance - Added `GetShortcutConflictWindow()`, `SetShortcutConflictWindow()`, and `ClearShortcutConflictWindow()` methods for lifecycle management ### ShortcutConflictWindow.xaml.cs - Updated `WindowEx_Closed` event handler to call `App.ClearShortcutConflictWindow()` to properly clean up the singleton reference when the window is closed ### Updated all three entry points that create ShortcutConflictWindow: - **ShortcutConflictControl.xaml.cs** (Dashboard conflict warning) - **ShortcutControl.xaml.cs** (Settings page shortcut controls) - **OobeOverview.xaml.cs** (OOBE overview page) Each location now checks if a window already exists using `App.GetShortcutConflictWindow()`: - If no window exists, creates a new one and registers it via `App.SetShortcutConflictWindow()` - If a window already exists, simply calls `Activate()` to bring it to the foreground ## Testing The fix ensures that: - ✅ Only one ShortcutConflictWindow can be open at a time - ✅ Clicking the shortcut conflict button when a window is already open activates the existing window instead of creating a duplicate - ✅ The window reference is properly cleared when closed, allowing a new instance to be created in future interactions Fixes #[issue_number] > [!WARNING] > > <details> > <summary>Firewall rules blocked me from connecting to one or more addresses (expand for details)</summary> > > #### I tried to connect to the following addresses, but was blocked by firewall rules: > > - `i1qvsblobprodcus353.vsblob.vsassets.io` > - Triggering command: `dotnet build PowerToys.Settings.csproj --configuration Release` (dns block) > > If you need me to access, download, or install something from one of these locations, you can either: > > - Configure [Actions setup steps](https://gh.io/copilot/actions-setup-steps) to set up my environment, which run before the firewall is enabled > - Add the appropriate URLs or hosts to the custom allowlist in this repository's [Copilot coding agent settings](https://github.com/microsoft/PowerToys/settings/copilot/coding_agent) (admins only) > > </details> <!-- START COPILOT CODING AGENT SUFFIX --> <details> <summary>Original prompt</summary> > > ---- > > *This section details on the original issue you should resolve* > > <issue_title>[Settings] Single Shortcuts Conflicts window</issue_title> > <issue_description>### Microsoft PowerToys version > > 0.95.0 > > ### Installation method > > GitHub > > ### Area(s) with issue? > > Settings > > ### Steps to reproduce > > Multiple shortcut conflicts window can be launched. > Should have the same behavior of OOBE window. > If shortcut conflicts window is already opened, pressing the button should bring the window in foreground. > > ### ✔️ Expected Behavior > > Single shortcuts conflicts window > > ### ❌ Actual Behavior > > Multiple shortcut conflicts window can be launched > > ### Additional Information > > _No response_ > > ### Other Software > > _No response_</issue_description> > > <agent_instructions>Settings ShortcutConflictWindow should have the same behavior of OobeWindow. > When ShortcutConflictWindow is already opened, activate that window instead of opening another one. </agent_instructions> > > ## Comments on the Issue (you are @copilot in this section) > > <comments> > </comments> > </details> Fixes microsoft/PowerToys#42437 <!-- START COPILOT CODING AGENT TIPS --> --- 💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click [here](https://survey3.medallia.com/?EAHeSx-AP01bZqG0Ld9QLQ) to start the survey. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: davidegiacometti <25966642+davidegiacometti@users.noreply.github.com> Co-authored-by: Davide Giacometti <davide.giacometti@outlook.it> Co-authored-by: Niels Laute <niels.laute@live.nl> Co-authored-by: vanzue <vanzue@outlook.com>
This commit is contained in:
@@ -55,6 +55,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
|
||||
// Flag to prevent toggle operations during sorting to avoid race conditions.
|
||||
private bool _isSorting;
|
||||
private bool _isDisposed;
|
||||
|
||||
private AllHotkeyConflictsData _allHotkeyConflictsData = new AllHotkeyConflictsData();
|
||||
|
||||
@@ -132,8 +133,18 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
|
||||
private void OnSettingsChanged(GeneralSettings newSettings)
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
dispatcher.TryEnqueue(() =>
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
generalSettingsConfig = newSettings;
|
||||
|
||||
// Update local field and notify UI if sort order changed
|
||||
@@ -149,8 +160,18 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
|
||||
protected override void OnConflictsUpdated(object sender, AllHotkeyConflictsEventArgs e)
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
dispatcher.TryEnqueue(() =>
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var allConflictData = e.Conflicts;
|
||||
foreach (var inAppConflict in allConflictData.InAppConflicts)
|
||||
{
|
||||
@@ -363,6 +384,11 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
/// </summary>
|
||||
public void ModuleEnabledChangedOnSettingsPage()
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore if this was triggered by a UI change that we're already handling.
|
||||
if (_isUpdatingFromUI)
|
||||
{
|
||||
@@ -391,6 +417,17 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
/// </summary>
|
||||
private void RefreshShortcutModules()
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dispatcher.HasThreadAccess)
|
||||
{
|
||||
_ = dispatcher.TryEnqueue(DispatcherQueuePriority.Normal, RefreshShortcutModules);
|
||||
return;
|
||||
}
|
||||
|
||||
ShortcutModules.Clear();
|
||||
ActionModules.Clear();
|
||||
|
||||
@@ -804,6 +841,12 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_isDisposed = true;
|
||||
base.Dispose();
|
||||
if (_settingsRepository != null)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user