From d8de5556b9f41a8944e4849c507796a71617f7ea Mon Sep 17 00:00:00 2001 From: Jumar Macato <16554748+jmacato@users.noreply.github.com> Date: Thu, 7 May 2026 20:01:36 +0800 Subject: [PATCH] Add back a thin automation peer for native menu bar. --- .../Peers/NativeMenuBarAutomationPeer.cs | 16 ++++ src/Avalonia.Controls/NativeMenuBar.cs | 3 + .../NativeMenuBarAutomationPeerTests.cs | 73 +++++++++++++++++++ 3 files changed, 92 insertions(+) create mode 100644 src/Avalonia.Controls/Automation/Peers/NativeMenuBarAutomationPeer.cs create mode 100644 tests/Avalonia.Controls.UnitTests/Automation/NativeMenuBarAutomationPeerTests.cs diff --git a/src/Avalonia.Controls/Automation/Peers/NativeMenuBarAutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/NativeMenuBarAutomationPeer.cs new file mode 100644 index 0000000000..4f03051118 --- /dev/null +++ b/src/Avalonia.Controls/Automation/Peers/NativeMenuBarAutomationPeer.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using System.Linq; +using Avalonia.Controls; +using Avalonia.LogicalTree; +using Avalonia.VisualTree; + +namespace Avalonia.Automation.Peers +{ + public class NativeMenuBarAutomationPeer(NativeMenuBar owner) : ControlAutomationPeer(owner) + { + protected override AutomationControlType GetAutomationControlTypeCore() + { + return AutomationControlType.MenuBar; + } + } +} diff --git a/src/Avalonia.Controls/NativeMenuBar.cs b/src/Avalonia.Controls/NativeMenuBar.cs index 022511bafa..ddb0b8136e 100644 --- a/src/Avalonia.Controls/NativeMenuBar.cs +++ b/src/Avalonia.Controls/NativeMenuBar.cs @@ -1,4 +1,5 @@ using System; +using Avalonia.Automation.Peers; using Avalonia.Controls.Metadata; using Avalonia.Controls.Primitives; using Avalonia.Controls.Templates; @@ -70,5 +71,7 @@ namespace Avalonia.Controls menu.Bind(ItemsControl.ItemsSourceProperty, topLevel.GetBindingObservable(NativeMenu.MenuProperty) .Select(v => v.GetValueOrDefault()?.Items))); } + + protected override AutomationPeer OnCreateAutomationPeer() => new NativeMenuBarAutomationPeer(this); } } diff --git a/tests/Avalonia.Controls.UnitTests/Automation/NativeMenuBarAutomationPeerTests.cs b/tests/Avalonia.Controls.UnitTests/Automation/NativeMenuBarAutomationPeerTests.cs new file mode 100644 index 0000000000..6586fb31d6 --- /dev/null +++ b/tests/Avalonia.Controls.UnitTests/Automation/NativeMenuBarAutomationPeerTests.cs @@ -0,0 +1,73 @@ +using System.Linq; +using Avalonia; +using Avalonia.Automation; +using Avalonia.Automation.Peers; +using Avalonia.Controls; +using Avalonia.Controls.Templates; +using Avalonia.UnitTests; +using Avalonia.VisualTree; +using Xunit; + +namespace Avalonia.Controls.UnitTests.Automation; + +public class NativeMenuBarAutomationPeerTests +{ + public class PeerCreation : ScopedTestBase + { + [Fact] + public void Creates_NativeMenuBarAutomationPeer() + { + var control = new NativeMenuBar { Template = CreateTemplate() }; + var peer = ControlAutomationPeer.CreatePeerForElement(control); + + Assert.IsType(peer); + } + + [Fact] + public void ControlType_Is_MenuBar() + { + var control = new NativeMenuBar { Template = CreateTemplate() }; + var peer = (NativeMenuBarAutomationPeer)ControlAutomationPeer.CreatePeerForElement(control); + + Assert.Equal(AutomationControlType.MenuBar, peer.GetAutomationControlType()); + } + } + + public class Children : ScopedTestBase + { + [Fact] + public void Exposes_Realized_MenuItems_Via_VisualChildren() + { + var control = new NativeMenuBar { Template = CreateTemplate() }; + control.ApplyTemplate(); + var menu = Assert.IsType(control.GetVisualChildren().Single()); + menu.ApplyTemplate(); + menu.Measure(Size.Infinity); + menu.Arrange(new Rect(0, 0, 300, 30)); + control.Measure(Size.Infinity); + control.Arrange(new Rect(0, 0, 300, 30)); + + var peer = (NativeMenuBarAutomationPeer)ControlAutomationPeer.CreatePeerForElement(control); + var presenterChildren = peer.GetChildren(); + + Assert.Equal(2, presenterChildren.Count); + Assert.All(presenterChildren, x => Assert.IsType(x)); + Assert.Equal("File", presenterChildren[0].GetName()); + Assert.Equal("Edit", presenterChildren[1].GetName()); + } + } + + private static FuncControlTemplate CreateTemplate() + { + return new FuncControlTemplate((_, ns) => + new Menu + { + Name = "PART_NativeMenuPresenter", + Items = + { + new MenuItem { Header = "File" }, + new MenuItem { Header = "Edit" }, + }, + }.RegisterInNameScope(ns)); + } +}