xaml-csharp-development-skill-for-avalonia

Visual Tree Inspection and Traversal

Table of Contents

  1. Scope and APIs
  2. Visual Tree Fundamentals
  3. Traversal and Query Patterns
  4. Hit Testing and Bounds Inspection
  5. Lifecycle and Root Awareness
  6. Debug Inspection Patterns
  7. Best Practices
  8. Troubleshooting

Scope and APIs

Primary APIs:

Reference source files:

Visual Tree Fundamentals

The visual tree is the rendered structure used for:

Key properties:

Use the visual tree when reasoning about on-screen behavior.

Traversal and Query Patterns

Ancestor/descendant queries

using Avalonia.Controls;
using Avalonia.VisualTree;

var scroll = myControl.FindAncestorOfType<ScrollViewer>();
var button = myRoot.FindDescendantOfType<Button>();

Enumerate ancestors

using Avalonia.VisualTree;

foreach (var ancestor in myControl.GetSelfAndVisualAncestors())
{
    Console.WriteLine(ancestor.GetType().Name);
}

Enumerate descendants

using Avalonia.VisualTree;

foreach (var descendant in myRoot.GetVisualDescendants())
{
    // inspection, diagnostics, selective filtering
}

Root/top-level lookup

using Avalonia.Controls;

TopLevel? host = TopLevel.GetTopLevel(myControl);

Hit Testing and Bounds Inspection

Point hit testing:

using Avalonia;
using Avalonia.VisualTree;

Point p = new Point(120, 40); // point in myRoot coordinate space
var first = myRoot.GetVisualAt(p);
var all = myRoot.GetVisualsAt(p, v => v.IsVisible);

Transformed bounds inspection:

using Avalonia.VisualTree;

var tb = myControl.GetTransformedBounds();
if (tb is { } bounds)
{
    var clip = bounds.Clip;
    var transform = bounds.Transform;
}

Use this when debugging clipping, transforms, or unexpected hit targets.

Lifecycle and Root Awareness

Attach/detach events are the correct points for visual-root-dependent work:

using Avalonia;

protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
    base.OnAttachedToVisualTree(e);
    // e.Root, e.Parent available here
}

protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
    base.OnDetachedFromVisualTree(e);
    // cleanup root-dependent subscriptions/resources
}

Guidance:

Debug Inspection Patterns

Quick visual tree dump helper:

using Avalonia.VisualTree;

static void DumpVisual(Visual visual, int depth = 0)
{
    Console.WriteLine($"{new string(' ', depth * 2)}{visual.GetType().Name}");
    foreach (var child in visual.GetVisualChildren())
    {
        DumpVisual(child, depth + 1);
    }
}

Use in diagnostics, tests, and runtime asserts for template/overlay bugs.

Best Practices

Troubleshooting

  1. FindAncestorOfType returns null unexpectedly:
    • Control is in another visual root (popup/overlay).
    • Query runs before attachment.
  2. GetVisualRoot() is null:
    • Element is not attached to visual tree yet.
  3. Hit testing misses expected element:
    • Wrong coordinate space.
    • Element filtered out by visibility/filter predicate.
    • Overlay/adorner consumes topmost hit.
  4. Traversal results fluctuate:
    • Template reapplication or virtualization changed realized visuals.