{"record":{"id":"0cf9cb71bd205b60","repo":"stride3d/stride","slug":"control-is-already-disposed","errorCode":null,"errorMessage":"Control is already disposed","messagePattern":"Control is already disposed","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/engine/Stride.Games/Desktop/WindowsMessageLoop.cs","lineNumber":98,"sourceCode":"            get\n            {\n                return control;\n            }\n            set\n            {\n                if (control == value) return;\n\n                // Remove any previous control\n                if (control != null && !switchControl)\n                {\n                    isControlAlive = false;\n                    control.Disposed -= ControlDisposed;\n                    controlHandle = IntPtr.Zero;\n                }\n\n                if (value != null && value.IsDisposed)\n                {\n                    throw new InvalidOperationException(\"Control is already disposed\");\n                }\n\n                control = value;\n                switchControl = true;\n            }\n        }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether the render loop should use the default <see cref=\"Application.DoEvents\"/> instead of a custom window message loop lightweight for GC. Default is false.\n        /// </summary>\n        /// <value><c>true</c> if the render loop should use the default <see cref=\"Application.DoEvents\"/> instead of a custom window message loop (default false); otherwise, <c>false</c>.</value>\n        /// <remarks>By default, RenderLoop is using a custom window message loop that is more lightweight than <see cref=\"Application.DoEvents\" /> to process windows event message. \n        /// Set this parameter to true to use the default <see cref=\"Application.DoEvents\"/>.</remarks>\n        public bool UseApplicationDoEvents { get; set; }\n\n        /// <summary>\n        /// Calls this method on each frame.\n        /// </summary>","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/engine/Stride.Games/Desktop/WindowsMessageLoop.cs#L80-L116","documentation":"The WindowsMessageLoop.Control setter validates that the control being attached as the message-loop target is not already disposed; assigning a disposed Control throws InvalidOperationException because the loop cannot pump messages from a destroyed window handle.","triggerScenarios":"Setting the loop's Control property (or constructing WindowsMessageLoop/Run) with a Form/Control whose IsDisposed is true — e.g. after the window was closed.","commonSituations":"Restarting a render loop after the form closed; holding a form reference past disposal; racing a background thread that starts the loop while the UI thread closes the window.","solutions":["Check control.IsDisposed before assigning it to the message loop","Create a fresh Form/Control instance if the old one was disposed","Synchronize with the UI thread (Invoke/BeginInvoke) so the loop isn't started with a mid-disposal control"],"exampleFix":"// before\nloop.Control = cachedForm; // may already be disposed\n// after\nif (cachedForm == null || cachedForm.IsDisposed)\n    cachedForm = new RenderForm(...);\nloop.Control = cachedForm;","handlingStrategy":"validation","validationCode":"if (control == null || control.IsDisposed)\n    throw new InvalidOperationException(\"Cannot attach a disposed or null control to the message loop\");\nloop.Control = control;","typeGuard":"bool IsUsableControl(Control c) => c is { IsDisposed: false };","tryCatchPattern":"try { loop.Control = control; } catch (InvalidOperationException) { control = new RenderForm(...); loop.Control = control; }","preventionTips":["Check IsDisposed before reusing cached form references","Marshal loop startup onto the UI thread to avoid races with form disposal"],"tags":["winforms","render-loop","disposed-object"],"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"}