Skip to content

Fix: UIA tree not visible for Avalonia content embedded via WinFormsAvaloniaControlHost#21422

Merged
MrJul merged 2 commits into
AvaloniaUI:masterfrom
AndreyPolovodov:fix/embeddable-root-uia-host-provider
May 26, 2026
Merged

Fix: UIA tree not visible for Avalonia content embedded via WinFormsAvaloniaControlHost#21422
MrJul merged 2 commits into
AvaloniaUI:masterfrom
AndreyPolovodov:fix/embeddable-root-uia-host-provider

Conversation

@AndreyPolovodov

Copy link
Copy Markdown
Contributor

What does the pull request do?

Fixes the UIA accessibility tree being invisible for Avalonia content hosted in WinForms/WPF via WinFormsAvaloniaControlHost. Tools like Inspect.exe, Accessibility Insights for Windows, Narrator and FlaUI see the embedded Avalonia HWND as an opaque [pane] with no children.

What is the current behavior?

EmbeddableControlRootAutomationPeer implements IEmbeddedRootProvider but not IRootProvider. In the Win32 backend, AutomationNode.Create only checks for IRootProvider to instantiate RootAutomationNode:

else if (peer.GetProvider<IRootProvider>() is not null)
    return new RootAutomationNode(peer);
else
    return new AutomationNode(peer);

Embedded roots fall into the last branch and get a plain AutomationNode that doesn't implement IRawElementProviderFragmentRoot and returns null from GetHostRawElementProvider (no UiaHostProviderFromHwnd call). UiaReturnRawElementProvider then responds to WM_GETOBJECT with E_FAIL (0x80004005) and the Avalonia subtree is missing from UIA.

What is the updated/expected behavior with this PR?

EmbeddableControlRootAutomationPeer also implements IRootProvider. AutomationNode.Create picks the RootAutomationNode path, UiaReturnRawElementProvider succeeds, and the embedded Avalonia tree is fully exposed to UIA clients.

Verified by hosting an Avalonia control in a WPF window through WindowsFormsHost -> WinFormsAvaloniaControlHost and inspecting it with Inspect.exe and Accessibility Insights for Windows: the full control tree is now reachable instead of a single [pane].

How was the solution implemented (if it's not obvious)?

IRootProvider and IEmbeddedRootProvider share GetFocus, GetPeerFromPoint and FocusChanged with identical signatures, so the existing implementation satisfies both. The only extra IRootProvider member, PlatformImpl, is added as an explicit interface implementation forwarding to Owner.PlatformImpl.

Checklist

…onPeer

Without IRootProvider, AutomationNode.Create falls back to the plain
AutomationNode which doesn't implement IRawElementProviderFragmentRoot
and returns null from GetHostRawElementProvider. As a result,
UiaReturnRawElementProvider responds with E_FAIL for the WM_GETOBJECT
sent to the embedded HWND, and the Avalonia automation tree is invisible
to UIA clients (Inspect.exe, Narrator, FlaUI etc.) when the control is
hosted via WinFormsAvaloniaControlHost.
@MrJul MrJul added bug os-windows area-accessibility backport-candidate-12.0.x Consider this PR for backporting to 12.0 branch labels May 22, 2026
@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.1.999-cibuild0065734-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@cla-avalonia

cla-avalonia commented May 22, 2026

Copy link
Copy Markdown
Collaborator
  • All contributors have signed the CLA.

@AndreyPolovodov

Copy link
Copy Markdown
Contributor Author

@cla-avalonia agree

@MrJul MrJul left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IRootProvider makes sense on EmbeddableControlRoot despite the name: that is a "true" root, i.e. it's backed by a ITopLevelImpl.

LGTM!

@MrJul MrJul added this pull request to the merge queue May 26, 2026
Merged via the queue into AvaloniaUI:master with commit 2e45cd0 May 26, 2026
12 checks passed
MrJul pushed a commit to MrJul/Avalonia that referenced this pull request May 28, 2026
…valoniaControlHost (AvaloniaUI#21422)

* [Automation] Add EmbeddableControlRootAutomationPeer tests

* [Automation] Implement IRootProvider on EmbeddableControlRootAutomationPeer

Without IRootProvider, AutomationNode.Create falls back to the plain
AutomationNode which doesn't implement IRawElementProviderFragmentRoot
and returns null from GetHostRawElementProvider. As a result,
UiaReturnRawElementProvider responds with E_FAIL for the WM_GETOBJECT
sent to the embedded HWND, and the Avalonia automation tree is invisible
to UIA clients (Inspect.exe, Narrator, FlaUI etc.) when the control is
hosted via WinFormsAvaloniaControlHost.
@MrJul MrJul added backported-12.0.x and removed backport-candidate-12.0.x Consider this PR for backporting to 12.0 branch labels May 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants