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
- Assign the ContextMenu via the ContextMenu property of an element (element.ContextMenu = menu) instead of adding it to a visual tree.
- If manual display is needed, wrap in/let WPF create the Popup and call menu.IsOpen = true rather than parenting it directly.
- Remove code that adds the ContextMenu as a child of a panel or window content.
- 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
- Attach ContextMenus only via the ContextMenu property
- Never add a ContextMenu to a Children/Content collection
- Detach from a previous owner before reassigning
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
- SR.CreateRootPopup_ChildHasVisualParent
- ' ' is not a Visual or Visual3D.
- ' ' must be the root element of a tree, but has a logical…
- Cannot reopen a popup in the closed event handler.
- inverse ? SR.Visual_NotADescendant : SR.Visual_NotAnAncestor
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)