The close hook (needs one small fix).
All editor windows share LoadingWindowBase, routes Closing -> virtual OnClosing() (LoadingWindowBase.cs).
Two catches, 1. it never passes the CancelEventArgs down, and the handler is async void and WPF requires e.Cancel to be set synchronously before the first await, so an async override could never veto anyway. The fix is the standard WPF shuffle:
- In LoadingWindowBase_Closing, synchronously call a new protected virtual bool CanClose() (default true). If false -> e.Cancel = true immediately, then kick off the async prompt.
- If the user confirms discard -> set a forceClose bypass flag and call this.Close() again. The re-entrant close passes the check. That flag also gets set on the save path (CommandEditorWindow already listens for the VM's save-completed event to close itself), so saving doesn't re-prompt.
Once base class is fixed, all the editor windows (commands, games, overlay widgets, etc.) can opt in by overriding CanClose().
One the modal side, DialogHelper.ShowConfirmation("You have unsaved changes..."), already wired up at highest evel, one call, returns bool.
A three-way Save/Discard/Cancel would need a custom dialog. Simple yes/no for now.
TBD/How to flag "dirty":
-
Snapshot-compare (cleaner): CommandEditorWindowViewModelBase can already materialize the full command from editor state (the guts of ValidateAndBuildCommand()). Serialize it with JSONSerializerHelper at window load, rebuild+serialize at close, compare strings. No per-property wiring at all. The catch, use the build path without Validate() so a half-edited invalid command doesn't pop error dialogs mid-close (treat "won't build" as dirty), and check whether rebuilding regenerates action GUIDs, if IDs churn per build, it would flag as "always dirty" and need to normalize them out of the comparison first.
-
Coarse event flag (dumb/fast): wire into PropertyChanged on the VM plus CollectionChanged on the actions list once, set dirty = true on anything. Likely false positives from UI-state properties flipping.
The close hook (needs one small fix).
All editor windows share LoadingWindowBase, routes Closing -> virtual OnClosing() (LoadingWindowBase.cs).
Two catches, 1. it never passes the CancelEventArgs down, and the handler is async void and WPF requires e.Cancel to be set synchronously before the first await, so an async override could never veto anyway. The fix is the standard WPF shuffle:
Once base class is fixed, all the editor windows (commands, games, overlay widgets, etc.) can opt in by overriding CanClose().
One the modal side, DialogHelper.ShowConfirmation("You have unsaved changes..."), already wired up at highest evel, one call, returns bool.
A three-way Save/Discard/Cancel would need a custom dialog. Simple yes/no for now.
TBD/How to flag "dirty":
Snapshot-compare (cleaner): CommandEditorWindowViewModelBase can already materialize the full command from editor state (the guts of ValidateAndBuildCommand()). Serialize it with JSONSerializerHelper at window load, rebuild+serialize at close, compare strings. No per-property wiring at all. The catch, use the build path without Validate() so a half-edited invalid command doesn't pop error dialogs mid-close (treat "won't build" as dirty), and check whether rebuilding regenerates action GUIDs, if IDs churn per build, it would flag as "always dirty" and need to normalize them out of the comparison first.
Coarse event flag (dumb/fast): wire into PropertyChanged on the VM plus CollectionChanged on the actions list once, set dirty = true on anything. Likely false positives from UI-state properties flipping.