dotnet/wpf · error · InvalidOperationException

SR.Visual_NoCommonAncestor

Error message

SR.Visual_NoCommonAncestor

What it means

Visual.TransformToDescendant (and related transform APIs) throws InvalidOperationException(SR.Visual_NoCommonAncestor) when the two visuals share no common visual ancestor, so no coordinate transform between them can be computed.

Solutions

  1. Ensure both visuals belong to the same visual tree (same window/popup) before transforming
  2. Wait until the target element is loaded/connected (handle Loaded event)
  3. Check FindCommonVisualAncestor logic: verify both are attached via Window.GetWindow / PresentationSource

Example fix

// before
var t = otherWindowElement.TransformToDescendant(this); // different window
// after
if (Window.GetWindow(otherWindowElement) == Window.GetWindow(this))
    var t = otherWindowElement.TransformToDescendant(this);
Defensive patterns

Strategy: validation

Validate before calling

bool SameTree(Visual a, Visual b) => Window.GetWindow(a) == Window.GetWindow(b) && PresentationSource.FromVisual(a) != null && PresentationSource.FromVisual(b) != null;

Type guard

bool CanTransform(Visual a, Visual b) => SameTree(a, b);

Try / catch

try { var t = source.TransformToDescendant(target); } catch (InvalidOperationException) { /* elements not in same tree */ }

Prevention

When it happens

Trigger: Calling TransformToDescendant(visual) where the target visual is in a different visual tree / has no common ancestor with this visual.

Common situations: Transforming between elements from different windows, popups, or an element not yet connected to the visual tree (e.g. before it is loaded).

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

Appendix: source

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

            return descendant.InternalTransformToAncestor(this, true);
        }


        /// <summary>
        /// The returned matrix can be used to transform coordinates from this Visual to
        /// the specified Visual.
        /// Returns null if no such transform exists due to a non-invertible Transform.
        /// </summary>
        /// <exception cref="ArgumentNullException">If visual is null.</exception>
        /// <exception cref="InvalidOperationException">If the Visuals are not connected.</exception>
        public GeneralTransform TransformToVisual(Visual visual)
        {
            DependencyObject ancestor = FindCommonVisualAncestor(visual);
            Visual ancestorAsVisual = ancestor as Visual;

            if (ancestorAsVisual == null)
            {
                throw new System.InvalidOperationException(SR.Visual_NoCommonAncestor);
            }

            GeneralTransform g0;
            Matrix m0;

            bool isSimple0 = this.TrySimpleTransformToAncestor(ancestorAsVisual,
                                                               false,
                                                               out g0,
                                                               out m0);

            GeneralTransform g1;
            Matrix m1;

            bool isSimple1 = visual.TrySimpleTransformToAncestor(ancestorAsVisual,
                                                                 true,
                                                                 out g1,
                                                                 out m1);

View on GitHub (pinned to 81131a70a4)