dotnet/wpf · error · ArgumentException

SR.Visual_NotChild

Error message

SR.Visual_NotChild

What it means

Visual.RemoveVisualChild throws ArgumentException(SR.Visual_NotChild) when the specified child visual is not actually a child of this visual (its _parent differs from this). The method only removes direct children.

Solutions

  1. Verify VisualTreeHelper.GetParent(child) == this before removing
  2. Guard removal with a parent check and skip if not a direct child
  3. Track child addition/removal in custom containers to avoid duplicate removals

Example fix

// before
parent.RemoveVisualChild(child);
// after
if (VisualTreeHelper.GetParent(child) == parent)
    parent.RemoveVisualChild(child);
Defensive patterns

Strategy: validation

Validate before calling

if (VisualTreeHelper.GetParent(child) != parent) return; // not a direct child

Type guard

bool IsDirectChild(Visual p, Visual c) => VisualTreeHelper.GetParent(c) == p;

Try / catch

try { parent.RemoveVisualChild(child); } catch (ArgumentException) { /* already removed or never a child */ }

Prevention

When it happens

Trigger: Calling RemoveVisualChild with a visual whose parent is a different visual, or with a visual that was never added; stale references after the tree changed.

Common situations: Double-removal of a child; removing a grandchild from an ancestor; container recycling where the child was already re-parented.

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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Visual.cs:2648

        /// <summary>
        /// DisconnectChild
        ///
        ///    Derived classes must call this method to notify the Visual layer that a
        ///    child was removed from the children collection. The Visual layer will then call
        ///    GetChildren to find out which child has been removed.
        ///
        /// </summary>
        protected void RemoveVisualChild(Visual child)
        {
            if (child == null || child._parent == null)
            {
                return;
            }

            if (child._parent != this)
            {
                throw new ArgumentException(SR.Visual_NotChild);
            }

            // invalid during a VisualTreeChanged event
            VisualDiagnostics.VerifyVisualTreeChange(this);

            VisualDiagnostics.OnVisualChildChanged(this, child, false);

            if (InternalVisual2DOr3DChildrenCount == 0)
            {
                SetFlags(false, VisualFlags.HasChildren);
            }

            //
            // Remove the child on all channels its current parent is marshalled to.
            //

            for (int i = 0; i < _proxy.Count; i++)
            {

View on GitHub (pinned to 81131a70a4)