dotnet/wpf · error · InvalidOperationException

inverse ? SR.Visual_NotADescendant : SR.Visual_NotAnAncestor

Error message

inverse ? SR.Visual_NotADescendant : SR.Visual_NotAnAncestor

What it means

Visual.TryTransformToAncestor/ancestor transform helpers throw InvalidOperationException with SR.Visual_NotAnAncestor (or Visual_NotADescendant when inverse) when, after walking the visual/visual3D ancestry, the target does not stand in the required ancestor/descendant relation.

Solutions

  1. Verify the relationship first (walk VisualTreeHelper.GetParent chain up to the target)
  2. Recompute the transform after any layout/re-parenting changes
  3. For 2D-in-3D content, use the containing Viewport2DVisual3D as the ancestor

Example fix

// before
var t = child.TransformToAncestor(sibling);
// after
bool isAncestor = false;
for (DependencyObject p = VisualTreeHelper.GetParent(child); p != null; p = VisualTreeHelper.GetParent(p))
    if (p == sibling) { isAncestor = true; break; }
if (isAncestor) { var t = child.TransformToAncestor(sibling); }
Defensive patterns

Strategy: validation

Validate before calling

bool IsAncestor(DependencyObject ancestor, DependencyObject node) { for (DependencyObject p = node; p != null; p = VisualTreeHelper.GetParent(p)) if (p == ancestor) return true; return false; }

Type guard

bool IsAncestorOf(Visual a, Visual v) => IsAncestor(a, v);

Try / catch

try { var t = child.TransformToAncestor(anc); } catch (InvalidOperationException) { /* not ancestor/descendant */ }

Prevention

When it happens

Trigger: Calling TransformToAncestor(a) where a is not an ancestor of this visual, or TransformToDescendant(d) where d is not a descendant; 2D/3D boundary cases where GetContainingVisual2D does not reach the given ancestor.

Common situations: Passing a sibling instead of an ancestor; element moved/re-parented between computing and transforming; mixing Viewport2DVisual3D content with ordinary 2D ancestry assumptions.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

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

                    if (embedded2Don3D)
                    {
                        visualForGenTransform = gAsVisual3D.Visual;
                    }
                    else
                    {
                        visualForGenTransform = this;
                        embedded2Don3D = true;
                    }

                    group.Children.Add(new GeneralTransform2DTo3DTo2D(gAsVisual3D, visualForGenTransform));

                    g = VisualTreeHelper.GetContainingVisual2D(gAsVisual3D);
                }
            }

            if (g != ancestor)
            {
                throw new System.InvalidOperationException(inverse ? SR.Visual_NotADescendant : SR.Visual_NotAnAncestor);
            }

            // At this point, we will have 0 or more transforms in the GeneralTransformGroup
            // and the matrix which, if not identity, should be appended to the GeneralTransformGroup.
            // If, as is commonly the case, this loop terminates without encountering a bitmap effect
            // we will simply use the Matrix.

            // Assert that a non-null group implies at least one child
            Debug.Assert((group == null) || (group.Children.Count > 0));

            // Do we have a group?
            if (group != null)
            {
                if (!m.IsIdentity)
                {
                    group.Children.Add(new MatrixTransform(m));
                }

View on GitHub (pinned to 81131a70a4)