Browse Source

Fix: UIA tree not visible for Avalonia content embedded via WinFormsAvaloniaControlHost (#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.
pull/21440/head
AndreyPolovodov 4 months ago
committed by GitHub
parent
commit
2e45cd0ea9
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 5
      src/Avalonia.Controls/Automation/Peers/EmbeddableControlRootAutomationPeer.cs
  2. 47
      tests/Avalonia.Controls.UnitTests/Automation/EmbeddableControlRootAutomationPeerTests.cs

5
src/Avalonia.Controls/Automation/Peers/EmbeddableControlRootAutomationPeer.cs

@ -5,11 +5,12 @@ using Avalonia.Automation.Peers;
using Avalonia.Automation.Provider;
using Avalonia.Controls.Embedding;
using Avalonia.Input;
using Avalonia.Platform;
using Avalonia.VisualTree;
namespace Avalonia.Controls.Automation.Peers
{
public class EmbeddableControlRootAutomationPeer : ContentControlAutomationPeer, IEmbeddedRootProvider
public class EmbeddableControlRootAutomationPeer : ContentControlAutomationPeer, IEmbeddedRootProvider, IRootProvider
{
private Control? _focus;
@ -24,6 +25,8 @@ namespace Avalonia.Controls.Automation.Peers
public new EmbeddableControlRoot Owner => (EmbeddableControlRoot)base.Owner;
ITopLevelImpl? IRootProvider.PlatformImpl => Owner.PlatformImpl;
public event EventHandler? FocusChanged;
public AutomationPeer? GetFocus() => _focus is object ? GetOrCreate(_focus) : null;

47
tests/Avalonia.Controls.UnitTests/Automation/EmbeddableControlRootAutomationPeerTests.cs

@ -0,0 +1,47 @@
using Avalonia.Automation.Peers;
using Avalonia.Automation.Provider;
using Avalonia.UnitTests;
using Xunit;
#nullable enable
namespace Avalonia.Controls.UnitTests.Automation
{
public class EmbeddableControlRootAutomationPeerTests : ScopedTestBase
{
[Fact]
public void Peer_Provides_IRootProvider()
{
using var services = new CompositorTestServices();
var peer = ControlAutomationPeer.CreatePeerForElement(services.TopLevel);
var rootProvider = peer.GetProvider<IRootProvider>();
Assert.NotNull(rootProvider);
Assert.Same(peer, rootProvider);
}
[Fact]
public void Peer_Still_Provides_IEmbeddedRootProvider()
{
using var services = new CompositorTestServices();
var peer = ControlAutomationPeer.CreatePeerForElement(services.TopLevel);
var embeddedRootProvider = peer.GetProvider<IEmbeddedRootProvider>();
Assert.NotNull(embeddedRootProvider);
}
[Fact]
public void IRootProvider_PlatformImpl_Returns_Owner_PlatformImpl()
{
using var services = new CompositorTestServices();
var peer = ControlAutomationPeer.CreatePeerForElement(services.TopLevel);
var rootProvider = peer.GetProvider<IRootProvider>();
Assert.NotNull(rootProvider);
Assert.Same(services.TopLevel.PlatformImpl, rootProvider!.PlatformImpl);
}
}
}
Loading…
Cancel
Save