Files
PowerToys/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Services/IAppStateService.cs
Michael Jolley 4337f8e5ff CmdPal: Make settings and app state immutable (#46451)
## Summary
 
 This PR refactors CmdPal settings/state to be immutable end-to-end.
 
 ### Core changes
 - Convert model types to immutable records / init-only properties:
   - `SettingsModel`
   - `AppStateModel`
   - `ProviderSettings`
   - `DockSettings`
   - `RecentCommandsManager`
- supporting settings types (fallback/hotkey/alias/top-level
hotkey/history items, etc.)
- Replace mutable collections with immutable equivalents where
appropriate:
   - `ImmutableDictionary<,>`
   - `ImmutableList<>`
 - Move mutation flow to atomic service updates:
- `ISettingsService.UpdateSettings(Func<SettingsModel, SettingsModel>)`
   - `IAppStateService.UpdateState(Func<AppStateModel, AppStateModel>)`
- Update ViewModels/managers/services to use copy-on-write (`with`)
patterns instead of in-place
mutation.
- Update serialization context + tests for immutable model graph
compatibility.
 
 ## Why
 
Issue #46437 is caused by mutable shared state being updated from
different execution paths/threads,
leading to race-prone behavior during persistence/serialization.
 
By making settings/app state immutable and using atomic swap/update
patterns, we remove in-place
mutation and eliminate this class of concurrency bug.
 
 ## Validation
 
 - Built successfully:
   - `Microsoft.CmdPal.UI.ViewModels`
   - `Microsoft.CmdPal.UI`
   - `Microsoft.CmdPal.UI.ViewModels.UnitTests`
 - Updated unit tests for immutable update patterns.
 
 Fixes #46437

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-27 17:54:58 +00:00

35 lines
1.1 KiB
C#

// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Windows.Foundation;
namespace Microsoft.CmdPal.UI.ViewModels.Services;
/// <summary>
/// Manages the lifecycle of <see cref="AppStateModel"/>: load, save, and change notification.
/// </summary>
public interface IAppStateService
{
/// <summary>
/// Gets the current application state instance.
/// </summary>
AppStateModel State { get; }
/// <summary>
/// Persists the current state to disk and raises <see cref="StateChanged"/>.
/// </summary>
void Save();
/// <summary>
/// Atomically applies a transformation to the current state, persists the result,
/// and raises <see cref="StateChanged"/>.
/// </summary>
void UpdateState(Func<AppStateModel, AppStateModel> transform);
/// <summary>
/// Raised after state has been saved to disk.
/// </summary>
event TypedEventHandler<IAppStateService, AppStateModel> StateChanged;
}