{"record":{"id":"0680b7c9aba45315","repo":"MahApps/MahApps.Metro","slug":"dialog-isn-t-visible-to-close","errorCode":null,"errorMessage":"Dialog isn't visible to close","messagePattern":"Dialog isn't visible to close","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/MahApps.Metro/Controls/Dialogs/ProgressDialogController.cs","lineNumber":174,"sourceCode":"        /// Sets the dialog's progress bar brush.\n        /// </summary>\n        /// <param name=\"brush\">The brush to use for the progress bar's foreground.</param>\n        public void SetProgressBarForegroundBrush(Brush brush)\n        {\n            this.WrappedDialog.Invoke(() => this.WrappedDialog.ProgressBarForeground = brush);\n        }\n\n        /// <summary>\n        /// Begins an operation to close the ProgressDialog.\n        /// </summary>\n        /// <returns>A task representing the operation.</returns>\n        public Task CloseAsync()\n        {\n            this.WrappedDialog.Invoke(() =>\n                {\n                    if (!this.WrappedDialog.IsVisible)\n                    {\n                        throw new InvalidOperationException(\"Dialog isn't visible to close\");\n                    }\n\n                    this.WrappedDialog.Dispatcher.VerifyAccess();\n                    this.WrappedDialog.KeyDown -= this.WrappedDialog_KeyDown;\n                    this.WrappedDialog.PART_NegativeButton!.Click -= this.PART_NegativeButton_Click;\n\n                    this.cancellationTokenRegistration.Dispose();\n                });\n\n            return this.CloseCallback()\n                       .ContinueWith(_ => this.WrappedDialog.Invoke(() =>\n                           {\n                               this.IsOpen = false;\n                               this.Closed?.Invoke(this, EventArgs.Empty);\n                           }));\n        }\n    }\n}","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/MahApps/MahApps.Metro/blob/72099e310bac2d12ac98fd7560b69679252519f5/src/MahApps.Metro/Controls/Dialogs/ProgressDialogController.cs#L156-L192","documentation":"Thrown by ProgressDialogController.CloseAsync when WrappedDialog.IsVisible is false. The controller is obtained from ShowProgressAsync, which already closes the dialog when its task completes or is cancelled; calling CloseAsync again finds the dialog no longer visible. It guards against double-close and orphaned event handler unsubscribes.","triggerScenarios":"Calling controller.CloseAsync() twice; calling CloseAsync after the negative/cancel button already dismissed the progress dialog; calling CloseAsync after the CancellationTokenSource triggered the dialog's internal close.","commonSituations":"A 'cancel' handler that calls both controller.CloseAsync() and cancels the token (which itself closes the dialog); awaiting ShowProgressAsync and then also calling CloseAsync; race between a work-task completion and an explicit close.","solutions":["Call CloseAsync exactly once; track an 'already closing' flag.","Do not call CloseAsync if the cancellation token already closed it — let ShowProgressAsync's completion handle it.","Guard the call: if (controller.IsOpen) await controller.CloseAsync(); — note IsOpen becomes false after close completes.","Avoid wiring both the negative button and an explicit CloseAsync to the same dismiss path."],"exampleFix":"// before\nvar controller = await this.ShowProgressAsync(\"...\", \"...\");\n// work done\ncancellationToken.Cancel();\nawait controller.CloseAsync(); // may throw - cancel already closed it\n\n// after\nvar controller = await this.ShowProgressAsync(\"...\", \"...\");\n// work done\nif (controller.IsOpen)\n{\n    await controller.CloseAsync();\n}","handlingStrategy":"validation","validationCode":"// Check IsOpen before closing; it flips to false after a successful close.\nif (controller.IsOpen)\n{\n    await controller.CloseAsync();\n}\n\n// Also avoid calling CloseAsync when a cancellation token already dismisses the dialog.","typeGuard":null,"tryCatchPattern":"try { await controller.CloseAsync(); }\ncatch (InvalidOperationException ex) when (ex.Message == \"Dialog isn't visible to close\")\n{\n    // Already closed (e.g. via cancel button or token). Safe to ignore.\n}","preventionTips":["Call CloseAsync exactly once per ShowProgressAsync result.","Do not call CloseAsync if the cancellation token or negative button already closed the dialog.","Track a 'closing' flag to prevent concurrent close paths."],"tags":["wpf","dialogs","mahapps","progress-dialog","lifecycle","double-close"],"backgroundTag":null,"analyzedSha":"72099e310bac2d12ac98fd7560b69679252519f5","analyzedAt":"2026-08-13T20:19:34.419Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}