dotnet/wpf · error

Cannot reopen a popup in the closed event handler.

Error message

Cannot reopen a popup in the closed event handler.

What it means

WPF's Popup throws this InvalidOperationException when code calls IsOpen=true (or Show) from inside the popup's Closed event handler. The popup caches a flag (CacheBits.OnClosedHandlerReopen) set while the Closed handler runs, and re-opening during close processing would corrupt the window lifecycle. You must wait until close processing finishes before re-showing.

Solutions

  1. Defer the reopen by posting it to the dispatcher: Dispatcher.BeginInvoke(() => popup.IsOpen = true, DispatcherPriority.Input) instead of setting IsOpen inside Closed.
  2. Restructure logic so the popup stays open (move/resize it) rather than closing and reopening.
  3. If the reopen is intentional and valid, ensure the Closed handler returned before setting IsOpen (e.g. via async continuation).

Example fix

// before
popup.Closed += (s, e) => popup.IsOpen = true; // throws
// after
popup.Closed += (s, e) =>
    Dispatcher.BeginInvoke(new Action(() => popup.IsOpen = true), DispatcherPriority.Input);
Defensive patterns

Strategy: try-catch

Validate before calling

// Cannot reliably pre-check; instead check the flag indirectly:
bool closing = popup.IsOpen == false; // only reopen after handler returns
if (!closing) popup.IsOpen = true;

Try / catch

try { popup.IsOpen = true; }
catch (InvalidOperationException ex) when (ex.Message.Contains("reopen")) {
    Dispatcher.BeginInvoke(new Action(() => popup.IsOpen = true), DispatcherPriority.Input);
}

Prevention

When it happens

Trigger: Setting popup.IsOpen = true (or calling SetCurrentValue(IsOpenProperty, true)) synchronously inside the Closed event handler or OnClosed override, e.g. to immediately relocate/re-show the popup.

Common situations: Developers chaining popups ('close this one, then open another'), implementing flyout animations that re-show the popup after a fade, or auto-reopen logic after a dismiss.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/a5b8b4b98f599900. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/Primitives/Popup.cs:351

        /// <summary>
        ///     Called when IsOpenProperty is changed on "d."
        /// </summary>
        private static void OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Popup popup = (Popup)d;

            // This is actually the current state and not necessary the desired state (i.e. old value)
            bool currentVisible = (popup._secHelper.IsWindowAlive() && (popup._asyncDestroy == null)) || (popup._asyncCreate != null);
            bool visible = (bool) e.NewValue;

            if (visible != currentVisible)
            {
                if (visible)
                {
                    // The popup wants to be visible

                    if (popup._cacheValid[(int)CacheBits.OnClosedHandlerReopen])
                        throw new InvalidOperationException(SR.PopupReopeningNotAllowed);

                    popup.CancelAsyncDestroy();

                    // Cancel any pending async create requests, we're creating now
                    popup.CancelAsyncCreate();
                    popup.CreateWindow(false /*asyncCall*/);

                    // It is possible that the popup is destroyed by CreateWindow or one of its callbacks
                    if (popup._secHelper.IsWindowAlive())
                    {
                        // Close the popup when it is unloaded from the visual tree
                        if (CloseOnUnloadedHandler == null)
                        {
                            CloseOnUnloadedHandler = new RoutedEventHandler(CloseOnUnloaded);
                        }

                        popup.Unloaded += CloseOnUnloadedHandler;
                    }

View on GitHub (pinned to 81131a70a4)