dotnet/wpf · error · InvalidOperationException
SR.CreateRootPopup_ChildHasVisualParent
Error message
SR.CreateRootPopup_ChildHasVisualParent
What it means
Sibling check in Popup.CreateRootPopupInternal: after verifying there is no logical parent, it also verifies the child has no visual parent (VisualTreeHelper.GetParent). An element already in a visual tree cannot be adopted as a popup root, so WPF throws InvalidOperationException. This typically fires when the element was rendered somewhere else.
Solutions
- Remove the element from its current visual parent (e.g. panel.Children.Remove(el)) before assigning it as the popup Child.
- Clone or instantiate a new element instead of moving the rendered one.
- Check VisualTreeHelper.GetParent(child) == null in a debug assertion before assigning Child.
Example fix
// before popup.Child = this.someGrid; // someGrid still in window's visual tree // after rootPanel.Children.Remove(this.someGrid); popup.Child = this.someGrid;
Defensive patterns
Strategy: validation
Validate before calling
if (VisualTreeHelper.GetParent(child) != null)
throw new InvalidOperationException("Element still has a visual parent"); Type guard
bool HasVisualParent(UIElement el) => VisualTreeHelper.GetParent(el) != null;
Try / catch
try { popup.Child = element; }
catch (InvalidOperationException) {
(VisualTreeHelper.GetParent(element) as Panel)?.Children.Remove(element);
popup.Child = element;
} Prevention
- Remove the element from its containing panel before moving it into a popup
- Avoid keeping references to rendered elements for reuse elsewhere
- Assert child is parentless in debug builds
When it happens
Trigger: Assigning an element that is live in another visual tree (e.g. rendered inside a Window, ControlTemplate, or another Popup) as the Child of a Popup, ToolTip, or ContextMenu via CreateRootPopup/Child setter.
Common situations: Moving a visible control into a popup at runtime; sharing one Border/Grid element between a window and a popup; reusing template parts.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- ' ' must be the root element of a tree, but has a logical…
- SR.ElementMustBeInPopup (ContextMenu)
- ' ' is not a Visual or Visual3D.
- 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/aed364b085949af9.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/Primitives/Popup.cs:895
/// <param name="child">The element to be the child of the popup.</param>
/// <param name="bindTreatMousePlacementAsBottomProperty">Whether to bind TreatMousePlacementAsBottomProperty to the child's FromKeyboard property</param>
internal static void CreateRootPopupInternal(Popup popup, UIElement child, bool bindTreatMousePlacementAsBottomProperty)
{
ArgumentNullException.ThrowIfNull(popup);
ArgumentNullException.ThrowIfNull(child);
Debug.Assert(!bindTreatMousePlacementAsBottomProperty || child is ToolTip, "child must be a Tooltip to bind TreatMousePlacementAsBottomProperty");
// When we get here, the Child must not have already been visually or logically parented.
object currentParent = null;
if ((currentParent = LogicalTreeHelper.GetParent(child)) != null)
{
throw new InvalidOperationException(SR.Format(SR.CreateRootPopup_ChildHasLogicalParent, child, currentParent));
}
if ((currentParent = VisualTreeHelper.GetParent(child)) != null)
{
throw new InvalidOperationException(SR.Format(SR.CreateRootPopup_ChildHasVisualParent, child, currentParent));
}
// PlacementTarget must be set before hooking up the child so that resource
// lookups can work. The Popup for tooltip and context menu isn't in the tree
// so FE relies on GetUIParentCore to return the placement target as the
// effective logical parent
Binding binding = new Binding("PlacementTarget")
{
Mode = BindingMode.OneWay,
Source = child
};
popup.SetBinding(PlacementTargetProperty, binding);
// NOTE: this will hook up child as a logical child of Popup.
// If at a later date this is not desired, then modify the hookup to avoid the logical hookup.
//
// NOTE: Logical linking is necessary if property invalidations are to propagate down
// the tree into the child (unless at a later date an alternate method has been created).View on GitHub (pinned to 81131a70a4)