{"record":{"id":"34252341bdd4f5d6","repo":"stride3d/stride","slug":"a-resize-operation-was-already-in-progress","errorCode":null,"errorMessage":"A resize operation was already in progress.","messagePattern":"A resize operation was already in progress\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/editor/Stride.Assets.Presentation/AssetEditors/SpriteEditor/ViewModels/ResizableSpriteInfoPartViewModel.cs","lineNumber":47,"sourceCode":"            Sprite.Editor.Viewport.PropertyChanged -= ViewportPropertyChanged;\n            base.Destroy();\n        }\n\n        protected abstract void OnResizeDelta(ResizingDirection direction, double horizontalChange, double verticalChange);\n\n        protected abstract string ComputeTransactionName(ResizingDirection direction, double horizontalChange, double verticalChange);\n\n        private void ViewportPropertyChanged(object sender, PropertyChangedEventArgs e)\n        {\n            var viewport = (ViewportViewModel)sender;\n            if (e.PropertyName == nameof(ViewportViewModel.ScaleFactor))\n                ScaleFactor = viewport.ScaleFactor;\n        }\n\n        void IResizingTarget.OnResizingStarted(ResizingDirection direction)\n        {\n            if (resizingTransaction != null || resizingContext != null)\n                throw new InvalidOperationException(\"A resize operation was already in progress.\");\n\n            resizingTransaction = UndoRedoService.CreateTransaction();\n            resizingContext = SynchronizationContext.Current;\n        }\n\n        void IResizingTarget.OnResizingDelta(ResizingDirection direction, double horizontalChange, double verticalChange)\n        {\n            if (resizingTransaction == null || resizingContext == null)\n                throw new InvalidOperationException(\"No resize operation in progress.\");\n\n            // The synchronization context has changed here, we must signal we intentionnally continue an existing transaction.\n            resizingTransaction.Continue();\n            OnResizeDelta(direction, horizontalChange, verticalChange);\n        }\n\n        void IResizingTarget.OnResizingCompleted(ResizingDirection direction, double horizontalChange, double verticalChange)\n        {\n            if (resizingTransaction == null || resizingContext == null)","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/editor/Stride.Assets.Presentation/AssetEditors/SpriteEditor/ViewModels/ResizableSpriteInfoPartViewModel.cs#L29-L65","documentation":"ResizableSpriteInfoPartViewModel.OnResizingStarted begins a sprite resize transaction by creating an undo transaction and capturing the synchronization context. It throws InvalidOperationException if a resize transaction or context is already active, enforcing one resize at a time.","triggerScenarios":"OnResizingStarted invoked while resizingTransaction != null or resizingContext != null — e.g. a second resizing gesture started without the previous one finishing (missing OnResizingEnded), or concurrent pointer/capture events.","commonSituations":"Mouse capture glitches in the sprite editor where the end-resize event is lost; overlapping resize gestures from different input sources; UI re-entrancy during an in-flight transaction.","solutions":["Ensure OnResizingEnded is always called (even on cancel/lost focus) so the previous transaction and context are cleared.","Cancel/complete the in-progress transaction before starting a new resize.","Guard input handling so a new resize gesture cannot begin while one is active (ignore or abort the second)."],"exampleFix":"// before\nif (resizingTransaction != null || resizingContext != null)\n    throw new InvalidOperationException(\"A resize operation was already in progress.\");\n// after\nif (resizingTransaction != null)\n{\n    UndoRedoService.CancelTransaction(); // or commit it\n    resizingTransaction = null;\n    resizingContext = null;\n}\nresizingTransaction = UndoRedoService.CreateTransaction();\nresizingContext = SynchronizationContext.Current;","handlingStrategy":"try-catch","validationCode":"// ensure no gesture is active before starting a new one\nif (spriteVm.ResizingInProgress) return; // expose or track this flag at the call site","typeGuard":"static bool CanStartResize(ResizableSpriteInfoPartViewModel vm) => !vm.IsResizing; // wrap the private transaction/context state","tryCatchPattern":"try { ((IResizingTarget)spriteVm).OnResizingStarted(direction); }\ncatch (InvalidOperationException ex) when (ex.Message == \"A resize operation was already in progress.\") { AbortCurrentGesture(); }","preventionTips":["Always pair OnResizingStarted with OnResizingEnded, including on cancel and lost mouse capture.","Ignore new resize gestures while one is active.","Clear transaction/context on editor state resets (undo, redo, asset reload)."],"tags":["invalid-state-transition","sprite-editor","concurrent-operation"],"backgroundTag":"invalid-state-transition","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}