MahApps/MahApps.Metro · error · InvalidOperationException

The provided dialog is already visible in the specified wind

Error message

The provided dialog is already visible in the specified window.

What it means

Thrown by ShowMetroDialogAsync when the dialog instance is already present in either the window's active or inactive dialog container. MahApps.Metro enforces one logical instance per window to prevent double-overlay and duplicate focus capture. The guard runs before overlay/font setup so a re-show would corrupt the dialog z-order stack.

Source

Thrown at src/MahApps.Metro/Controls/Dialogs/DialogManager.cs:301

        /// <returns>A task representing the operation.</returns>
        /// <exception cref="InvalidOperationException">The <paramref name="dialog"/> is already visible in the window.</exception>
        public static async Task ShowMetroDialogAsync(this MetroWindow window, BaseMetroDialog dialog, MetroDialogSettings? settings = null)
        {
            window.Dispatcher.VerifyAccess();

            if (window.metroActiveDialogContainer is null)
            {
                throw new InvalidOperationException("Active dialog container could not be found.");
            }

            if (window.metroInactiveDialogContainer is null)
            {
                throw new InvalidOperationException("Inactive dialog container could not be found.");
            }

            if (window.metroActiveDialogContainer.Children.Contains(dialog) || window.metroInactiveDialogContainer.Children.Contains(dialog))
            {
                throw new InvalidOperationException("The provided dialog is already visible in the specified window.");
            }

            settings ??= dialog.DialogSettings;

            await HandleOverlayOnShowAsync(settings, window);

            SetDialogFontSizes(settings, dialog);

            dialog.SizeChangedHandler = SetupAndAddDialog(window, dialog);

            await dialog.WaitForLoadAsync();

            DialogOpened?.Invoke(window, new DialogStateChangedEventArgs(dialog));
        }

        /// <summary>
        /// Adds a Metro Dialog instance of the given type to the specified window and makes it visible asynchronously.
        /// If you want to wait until the user has closed the dialog, use <see cref="BaseMetroDialog.WaitUntilUnloadedAsync"/>

View on GitHub (pinned to 72099e310b)

Solutions

  1. Track dialog lifetime: set a field to the dialog after showing and null it after HideMetroDialogAsync completes, and guard the show call on that field being null.
  2. Debounce/guard the entry point (e.g. disable the invoking button or a CanExecute check) while a dialog is already open.
  3. Create a fresh dialog instance per show instead of reusing the same BaseMetroDialog object.
  4. Before re-showing, check window metroActiveDialogContainer/metroInactiveDialogContainer Children.Contains — though these are internal, prefer the lifecycle guard.

Example fix

// before
private SettingsDialog? _settings;
private async void OnSettingsClick(object s, RoutedEventArgs e)
{
    await this.ShowMetroDialogAsync(_settings ??= new SettingsDialog(this));
}

// after
private SettingsDialog? _settings;
private async void OnSettingsClick(object s, RoutedEventArgs e)
{
    if (_settings is not null) return;
    _settings = new SettingsDialog(this);
    try { await this.ShowMetroDialogAsync(_settings); }
    finally { await this.HideMetroDialogAsync(_settings); _settings = null; }
}
Defensive patterns

Strategy: validation

Validate before calling

// Guard against re-showing a dialog already managed by the window.
// metroActiveDialogContainer / metroInactiveDialogContainer are internal,
// so track shown state yourself before calling ShowMetroDialogAsync.
private BaseMetroDialog? _openDialog;

async Task ShowOnceAsync(MetroWindow window, BaseMetroDialog dialog)
{
    if (_openDialog is not null) return;          // already showing something
    _openDialog = dialog;
    try { await window.ShowMetroDialogAsync(dialog); }
    catch { _openDialog = null; throw; }
}

Prevention

When it happens

Trigger: Calling window.ShowMetroDialogAsync(sameDialogInstance) twice without an intervening HideMetroDialogAsync; re-showing a dialog from a click handler that already fired; awaiting ShowMetroDialogAsync then calling it again on the same reference in a continuation.

Common situations: A 'Show Settings' button whose handler isn't debounced and fires twice on rapid double-click; reusing a cached BaseMetroDialog field across open/close cycles; calling ShowMetroDialogAsync from both a command and a window event with overlapping async execution.

Related errors


AI-assisted analysis of MahApps/MahApps.Metro@72099e310b (2026-08-13). Data as JSON: /api/errors/3358949744b4d622. Report an issue: GitHub.