dotnet/wpf · error · InvalidOperationException

SR.ElementMustBeInPopup (ContextMenu)

Error message

SR.ElementMustBeInPopup (ContextMenu)

What it means

A ContextMenu must be rooted in a Popup; WPF enforces this when the menu's visual parent changes. If OnVisualParentChanged finds the ContextMenu has gained a visual parent but is not rooted in a Popup (_parentPopup), it throws InvalidOperationException(SR.ElementMustBeInPopup). This preserves the assumption that context menus are hosted by the Popup plumbing.

Solutions

  1. Assign the ContextMenu via the ContextMenu property of an element (element.ContextMenu = menu) instead of adding it to a visual tree.
  2. If manual display is needed, wrap in/let WPF create the Popup and call menu.IsOpen = true rather than parenting it directly.
  3. Remove code that adds the ContextMenu as a child of a panel or window content.
  4. If moving the menu between owners, detach from the old owner first so the visual parent does not change while un-rooted.

Example fix

// before
stackPanel.Children.Add(myContextMenu); // throws
// after
myButton.ContextMenu = myContextMenu;
Defensive patterns

Strategy: validation

Validate before calling

bool safe = !IsInVisualTree(myContextMenu); // only attach via ContextMenu property
static bool IsInVisualTree(DependencyObject d) { DependencyObject p = d; while ((p = VisualTreeHelper.GetParent(p)) != null) return true; return false; }

Type guard

static bool CanAttachToVisualTree(ContextMenu m) => Popup.IsRootedInPopup(null, m); // false unless popup-managed

Try / catch

try
{
    panel.Children.Add(menu); // do not do this
}
catch (InvalidOperationException)
{
    target.ContextMenu = menu; // correct attachment
}

Prevention

When it happens

Trigger: Adding a ContextMenu directly to a visual tree as a child of another element (e.g. panel.Children.Add(contextMenu) or setting it as content) so its visual parent is not a Popup.

Common situations: Re-parenting a ContextMenu into a Grid/Canvas in code, moving a ContextMenu between controls in a way that attaches it to the visual tree, or template scenarios that accidentally place the menu in the tree.

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/0e869973cecee06f. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ContextMenu.cs:678

        }

        private static void OnAccessKeyPressed(object sender, AccessKeyPressedEventArgs e)
        {
            e.Scope = sender;
            e.Handled = true;
        }

        /// <summary>
        /// Called when this element's visual parent changes
        /// </summary>
        /// <param name="oldParent"></param>
        protected internal override void OnVisualParentChanged(DependencyObject oldParent)
        {
            base.OnVisualParentChanged(oldParent);

            if (!Popup.IsRootedInPopup(_parentPopup, this))
            {
                throw new InvalidOperationException(SR.Format(SR.ElementMustBeInPopup, "ContextMenu"));
            }
        }

        internal override void OnAncestorChanged()
        {
            base.OnAncestorChanged();

            if (!Popup.IsRootedInPopup(_parentPopup, this))
            {
                throw new InvalidOperationException(SR.Format(SR.ElementMustBeInPopup, "ContextMenu"));
            }
        }

        #endregion

        #region Private Fields

        private Popup _parentPopup;

View on GitHub (pinned to 81131a70a4)