[Windows] Add Automation Id support for Layouts. #35562
Conversation
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 35562Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 35562" |
|
Hey there @@SubhikshaSf4851! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed. |
|
/review -b feature/regression-check -p windows |
MauiBot
left a comment
There was a problem hiding this comment.
🤖 Automated review — alternative fix proposed
The expert-reviewer evaluation compared the PR fix against #2 automatically generated candidates and selected try-fix-2 as the strongest fix.
Why: try-fix-2 closes the full scope of issue #4715 (Layouts, ContentView, and Border) by moving OnCreateAutomationPeer from LayoutPanel to MauiPanel, preserves the PR's UIA quality (ClassName=Grid/VStack/..., ControlType=Pane, IsKeyboardFocusable=false), aligns IsControlElement/IsContentElement with the cross-platform opt-in convention, and explicitly raises UIA property-changed events on runtime AutomationId changes. Same one-line PublicAPI footprint as the PR (the line moves rather than grows).
Please consider applying the candidate diff below (or use it as guidance). Once you push an update, this workflow will re-trigger and re-evaluate.
Candidate diff (`try-fix-2`)
diff --git a/src/Controls/tests/DeviceTests/Elements/Layout/LayoutTests.Windows.cs b/src/Controls/tests/DeviceTests/Elements/Layout/LayoutTests.Windows.cs
index b9d56dcb72..21395ceaf2 100644
--- a/src/Controls/tests/DeviceTests/Elements/Layout/LayoutTests.Windows.cs
+++ b/src/Controls/tests/DeviceTests/Elements/Layout/LayoutTests.Windows.cs
@@ -6,7 +6,9 @@ using System.Threading.Tasks;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Handlers;
+using Microsoft.Maui.Hosting;
using Microsoft.Maui.Platform;
+using Microsoft.UI.Xaml.Automation.Peers;
using Xunit;
namespace Microsoft.Maui.DeviceTests
@@ -26,5 +28,136 @@ namespace Microsoft.Maui.DeviceTests
Assert.Equal(view.InputTransparent, !handler.PlatformView.IsHitTestVisible);
}
}
+
+ void SetupLayoutBuilder()
+ {
+ EnsureHandlerCreated(builder =>
+ {
+ builder.ConfigureMauiHandlers(handlers =>
+ {
+ handlers.AddHandler<Grid, LayoutHandler>();
+ handlers.AddHandler<VerticalStackLayout, LayoutHandler>();
+ handlers.AddHandler<HorizontalStackLayout, LayoutHandler>();
+ handlers.AddHandler<AbsoluteLayout, LayoutHandler>();
+ handlers.AddHandler<FlexLayout, LayoutHandler>();
+ handlers.AddHandler<StackLayout, LayoutHandler>();
+ });
+ });
+ }
+
+ [Fact(DisplayName = "LayoutPanel creates a MauiLayoutAutomationPeer")]
+ public async Task LayoutPanelCreatesMauiLayoutAutomationPeer()
+ {
+ SetupLayoutBuilder();
+
+ var grid = new Grid();
+
+ await AttachAndRun(grid, (LayoutHandler handler) =>
+ {
+ var peer = FrameworkElementAutomationPeer.CreatePeerForElement(handler.PlatformView);
+ Assert.IsType<MauiLayoutAutomationPeer>(peer);
+ });
+ }
+
+ [Fact(DisplayName = "LayoutPanel AutomationPeer control type is Pane")]
+ public async Task LayoutPanelAutomationPeerControlTypeIsPane()
+ {
+ SetupLayoutBuilder();
+
+ var grid = new Grid();
+
+ await AttachAndRun(grid, (LayoutHandler handler) =>
+ {
+ var peer = FrameworkElementAutomationPeer.CreatePeerForElement(handler.PlatformView);
+ Assert.Equal(AutomationControlType.Pane, peer.GetAutomationControlType());
+ });
+ }
+
+ [Theory(DisplayName = "LayoutPanel class name reflects cross-platform layout type")]
+ [InlineData(typeof(Grid), "Grid")]
+ [InlineData(typeof(VerticalStackLayout), "VerticalStackLayout")]
+ [InlineData(typeof(HorizontalStackLayout), "HorizontalStackLayout")]
+ [InlineData(typeof(AbsoluteLayout), "AbsoluteLayout")]
+ [InlineData(typeof(FlexLayout), "FlexLayout")]
+ [InlineData(typeof(StackLayout), "StackLayout")]
+ public async Task LayoutPanelClassNameReflectsCrossPlatformType(Type layoutType, string expectedClassName)
+ {
+ SetupLayoutBuilder();
+
+ var layout = (Layout)Activator.CreateInstance(layoutType)!;
+
+ // FlexLayout._root is only initialized when it has a MAUI parent.
+ // Wrap it in a VerticalStackLayout so OnParentSet() fires before layout runs.
+ Layout root = layout is FlexLayout
+ ? new VerticalStackLayout { layout }
+ : layout;
+
+ await AttachAndRun(root, (LayoutHandler handler) =>
+ {
+ // For FlexLayout, find the inner FlexLayout's platform view via its handler
+ var targetView = layout is FlexLayout
+ ? (layout.Handler as LayoutHandler)?.PlatformView ?? handler.PlatformView
+ : handler.PlatformView;
+
+ var peer = FrameworkElementAutomationPeer.CreatePeerForElement(targetView);
+ Assert.Equal(expectedClassName, peer.GetClassName());
+ });
+ }
+
+ [Theory(DisplayName = "LayoutPanel with AutomationId is exposed in automation tree")]
+ [InlineData(true)]
+ [InlineData(false)]
+ public async Task LayoutPanelWithAutomationIdIsExposedInTree(bool hasAutomationId)
+ {
+ SetupLayoutBuilder();
+
+ var grid = new Grid();
+ if (hasAutomationId)
+ grid.AutomationId = "TestGrid";
+
+ await AttachAndRun(grid, (LayoutHandler handler) =>
+ {
+ var peer = FrameworkElementAutomationPeer.CreatePeerForElement(handler.PlatformView);
+ Assert.Equal(hasAutomationId, peer.IsContentElement());
+ });
+ }
+
+ [Fact(DisplayName = "LayoutPanel AutomationPeer is not keyboard focusable")]
+ public async Task LayoutPanelAutomationPeerIsNotKeyboardFocusable()
+ {
+ SetupLayoutBuilder();
+
+ var grid = new Grid();
+
+ await AttachAndRun(grid, (LayoutHandler handler) =>
+ {
+ var peer = FrameworkElementAutomationPeer.CreatePeerForElement(handler.PlatformView);
+ Assert.False(peer.IsKeyboardFocusable());
+ });
+ }
+
+ [Fact(DisplayName = "LayoutPanel IsControlElement and IsContentElement update when AutomationId is set at runtime")]
+ public async Task LayoutPanelAutomationPeerUpdatesWhenAutomationIdChangesAtRuntime()
+ {
+ SetupLayoutBuilder();
+
+ var grid = new Grid();
+
+ await AttachAndRun(grid, (LayoutHandler handler) =>
+ {
+ var peer = FrameworkElementAutomationPeer.CreatePeerForElement(handler.PlatformView);
+
+ // Initially no AutomationId — should NOT be exposed
+ Assert.False(peer.IsContentElement());
+
+ // Set AutomationId at runtime — should now be exposed.
+ // Note: MAUI AutomationId is write-once (Element.cs enforces this),
+ // so we can only test the transition from unset → set, not set → cleared.
+ grid.AutomationId = "DynamicGrid";
+ Assert.True(peer.IsContentElement());
+ });
+ }
}
}
+
+
diff --git a/src/Core/src/Platform/Windows/MauiPanel.cs b/src/Core/src/Platform/Windows/MauiPanel.cs
index a633abd76a..c3154445ff 100644
--- a/src/Core/src/Platform/Windows/MauiPanel.cs
+++ b/src/Core/src/Platform/Windows/MauiPanel.cs
@@ -2,6 +2,7 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Maui.Graphics;
+using Microsoft.UI.Xaml.Automation.Peers;
using Microsoft.UI.Xaml.Controls;
using WSize = global::Windows.Foundation.Size;
@@ -79,5 +80,10 @@ namespace Microsoft.Maui.Platform
return null;
}
+
+ protected override AutomationPeer OnCreateAutomationPeer()
+ {
+ return new MauiPanelAutomationPeer(this);
+ }
}
}
diff --git a/src/Core/src/Platform/Windows/MauiPanelAutomationPeer.cs b/src/Core/src/Platform/Windows/MauiPanelAutomationPeer.cs
new file mode 100644
index 0000000000..ba4b9d9ae4
--- /dev/null
+++ b/src/Core/src/Platform/Windows/MauiPanelAutomationPeer.cs
@@ -0,0 +1,51 @@
+#nullable enable
+using Microsoft.UI.Xaml.Automation;
+using Microsoft.UI.Xaml.Automation.Peers;
+using Microsoft.UI.Xaml.Controls;
+
+namespace Microsoft.Maui.Platform
+{
+ // TODO: Make this class public in .NET11.0
+ internal partial class MauiPanelAutomationPeer : FrameworkElementAutomationPeer
+ {
+ internal MauiPanelAutomationPeer(MauiPanel owner) : base(owner) { }
+
+ // Prefer the cross-platform layout type ("Grid", "VerticalStackLayout", ...) when
+ // available. ContentPanel (used by ContentView, Border) has no CrossPlatformLayout,
+ // so fall back to the platform type name (e.g. "ContentPanel").
+ protected override string GetClassNameCore()
+ {
+ if (Owner is MauiPanel panel && panel.CrossPlatformLayout is not null)
+ {
+ return panel.CrossPlatformLayout.GetType().Name;
+ }
+
+ return Owner?.GetType().Name ?? nameof(Panel);
+ }
+
+ // Containers are structural ΓÇö Pane signals "grouping element" to screen readers.
+ protected override AutomationControlType GetAutomationControlTypeCore() => AutomationControlType.Pane;
+
+ // Containers are not interactive.
+ protected override bool IsKeyboardFocusableCore() => false;
+
+ // Match cross-platform convention (Android UpdateAutomationId only sets ContentDescription
+ // when AutomationId is non-empty): expose this container in the UI Automation tree only
+ // when the developer has explicitly opted in via AutomationId or SemanticProperties.Description
+ // (which is surfaced as AutomationProperties.Name).
+ protected override bool IsControlElementCore() => HasOptInMetadata();
+
+ protected override bool IsContentElementCore() => HasOptInMetadata();
+
+ bool HasOptInMetadata()
+ {
+ if (Owner is not Panel panel)
+ {
+ return false;
+ }
+
+ return !string.IsNullOrEmpty(AutomationProperties.GetAutomationId(panel))
+ || !string.IsNullOrEmpty(AutomationProperties.GetName(panel));
+ }
+ }
+}
diff --git a/src/Core/src/Platform/Windows/ViewExtensions.cs b/src/Core/src/Platform/Windows/ViewExtensions.cs
index 18fea5a6b1..9d6b53beea 100644
--- a/src/Core/src/Platform/Windows/ViewExtensions.cs
+++ b/src/Core/src/Platform/Windows/ViewExtensions.cs
@@ -138,9 +138,24 @@ namespace Microsoft.Maui.Platform
}
}
- public static void UpdateAutomationId(this FrameworkElement platformView, IView view) =>
+ public static void UpdateAutomationId(this FrameworkElement platformView, IView view)
+ {
AutomationProperties.SetAutomationId(platformView, view.AutomationId);
+ // For MauiPanel-derived containers the peer's IsControlElement/IsContentElement
+ // depend on AutomationId. Notify connected UI Automation clients so the cached
+ // peer state refreshes when AutomationId changes at runtime (#4715).
+ if (platformView is MauiPanel
+ && UI.Xaml.Automation.Peers.FrameworkElementAutomationPeer.FromElement(platformView) is MauiPanelAutomationPeer panelPeer)
+ {
+ bool exposed = !string.IsNullOrEmpty(view.AutomationId);
+ panelPeer.RaisePropertyChangedEvent(
+ AutomationElementIdentifiers.IsControlElementProperty, !exposed, exposed);
+ panelPeer.RaisePropertyChangedEvent(
+ AutomationElementIdentifiers.IsContentElementProperty, !exposed, exposed);
+ }
+ }
+
public static void UpdateSemantics(this FrameworkElement platformView, IView view)
{
var semantics = view.Semantics;
diff --git a/src/Core/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt b/src/Core/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt
index f02df3a74f..8d63e882c5 100644
--- a/src/Core/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt
+++ b/src/Core/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt
@@ -1,2 +1,3 @@
#nullable enable
+override Microsoft.Maui.Platform.MauiPanel.OnCreateAutomationPeer() -> Microsoft.UI.Xaml.Automation.Peers.AutomationPeer!
override Microsoft.Maui.Platform.MauiPasswordTextBox.OnCreateAutomationPeer() -> Microsoft.UI.Xaml.Automation.Peers.AutomationPeer!
|
/review -b feature/regression-check |
MauiBot
left a comment
There was a problem hiding this comment.
Expert Review — 8 findings
See inline comments for details.
|
|
||
| // Always expose in the Control View so that Narrator can read SemanticProperties.Description | ||
| // even when no AutomationId is set. | ||
| protected override bool IsControlElementCore() => true; |
| // when the cross-platform layout is unavailable. | ||
| protected override string GetClassNameCore() | ||
| { | ||
| if (Owner is MauiPanel panel) |
| { | ||
| if (Owner is MauiPanel panel) | ||
| { | ||
| return panel.CrossPlatformLayout?.GetType().Name ?? nameof(Panel); |
| protected override bool IsControlElementCore() => true; | ||
|
|
||
| // Expose in the Content View only when an AutomationId is explicitly set by the developer. | ||
| protected override bool IsContentElementCore() => HasAutomationId(); |
| namespace Microsoft.Maui.Platform | ||
| { | ||
| // TODO: Make this class public in .NET11.0 | ||
| internal partial class MauiLayoutAutomationPeer : FrameworkElementAutomationPeer |
| Canvas? _backgroundLayer; | ||
| public bool ClipsToBounds { get; set; } | ||
|
|
||
| protected override AutomationPeer OnCreateAutomationPeer() |
| await AttachAndRun(grid, (LayoutHandler handler) => | ||
| { | ||
| var peer = FrameworkElementAutomationPeer.CreatePeerForElement(handler.PlatformView); | ||
| Assert.IsType<MauiLayoutAutomationPeer>(peer); |
| await AttachAndRun(grid, (LayoutHandler handler) => | ||
| { | ||
| var peer = FrameworkElementAutomationPeer.CreatePeerForElement(handler.PlatformView); | ||
| Assert.Equal(hasAutomationId, peer.IsContentElement()); |
|
/review -b feature/regression-check -p windows |
1 similar comment
|
/review -b feature/regression-check -p windows |
🤖 AI Summary
📊 Review Session —
|
| Test | Without Fix (expect FAIL) | With Fix (expect PASS) |
|---|---|---|
📱 LayoutTests (LayoutPanelCreatesMauiLayoutAutomationPeer, LayoutPanelAutomationPeerControlTypeIsPane, LayoutPanelClassNameReflectsCrossPlatformType, LayoutPanelWithAutomationIdIsExposedInTree, LayoutPanelAutomationPeerIsNotKeyboardFocusable, LayoutPanelAutomationPeerUpdatesWhenAutomationIdChangesAtRuntime) Category=Layout |
✅ FAIL — 354s | ❌ FAIL — 217s |
🖥️ Issue4715 Issue4715 |
✅ FAIL — 597s | ✅ PASS — 503s |
🔴 Without fix — 📱 LayoutTests (LayoutPanelCreatesMauiLayoutAutomationPeer, LayoutPanelAutomationPeerControlTypeIsPane, LayoutPanelClassNameReflectsCrossPlatformType, LayoutPanelWithAutomationIdIsExposedInTree, LayoutPanelAutomationPeerIsNotKeyboardFocusable, LayoutPanelAutomationPeerUpdatesWhenAutomationIdChangesAtRuntime): FAIL ✅ · 354s
Determining projects to restore...
Restored D:\a\1\s\src\Controls\src\Xaml\Controls.Xaml.csproj (in 1.53 sec).
Restored D:\a\1\s\src\Controls\src\Xaml.Design\Controls.Xaml.Design.csproj (in 24 ms).
Restored D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj (in 73 ms).
Restored D:\a\1\s\src\Controls\src\Core.Design\Controls.Core.Design.csproj (in 5 ms).
Restored D:\a\1\s\src\Controls\src\BindingSourceGen\Controls.BindingSourceGen.csproj (in 96 ms).
Restored D:\a\1\s\src\Controls\Maps\src\Controls.Maps.csproj (in 95 ms).
Restored D:\a\1\s\src\Core\maps\src\Maps.csproj (in 77 ms).
Restored D:\a\1\s\src\TestUtils\src\DeviceTests\TestUtils.DeviceTests.csproj (in 3.28 sec).
Restored D:\a\1\s\src\TestUtils\src\DeviceTests.Runners\TestUtils.DeviceTests.Runners.csproj (in 346 ms).
Restored D:\a\1\s\src\TestUtils\src\DeviceTests.Runners.SourceGen\TestUtils.DeviceTests.Runners.SourceGen.csproj (in 3.2 sec).
Restored D:\a\1\s\src\Graphics\src\Graphics\Graphics.csproj (in 39 ms).
Restored D:\a\1\s\src\Graphics\src\Graphics.Win2D\Graphics.Win2D.csproj (in 11 ms).
Restored D:\a\1\s\src\Essentials\src\Essentials.csproj (in 27 ms).
Restored D:\a\1\s\src\Core\tests\DeviceTests.Shared\Core.DeviceTests.Shared.csproj (in 45 ms).
Restored D:\a\1\s\src\Core\src\Core.csproj (in 66 ms).
Restored D:\a\1\s\src\Controls\tests\DeviceTests\Controls.DeviceTests.csproj (in 43.69 sec).
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Graphics -> D:\a\1\s\artifacts\bin\Graphics\Release\net10.0-windows10.0.19041.0\Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Graphics.Win2D -> D:\a\1\s\artifacts\bin\Graphics.Win2D\Release\net10.0-windows10.0.19041.0\Microsoft.Maui.Graphics.Win2D.WinUI.Desktop.dll
Essentials -> D:\a\1\s\artifacts\bin\Essentials\Release\net10.0-windows10.0.19041.0\Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Core -> D:\a\1\s\artifacts\bin\Core\Release\net10.0-windows10.0.19041.0\Microsoft.Maui.dll
Controls.BindingSourceGen -> D:\a\1\s\artifacts\bin\Controls.BindingSourceGen\Release\netstandard2.0\Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Controls.Core -> D:\a\1\s\artifacts\bin\Controls.Core\Release\net10.0-windows10.0.19041.0\Microsoft.Maui.Controls.dll
Maps -> D:\a\1\s\artifacts\bin\Maps\Release\net10.0-windows10.0.19041.0\Microsoft.Maui.Maps.dll
TestUtils.DeviceTests -> D:\a\1\s\artifacts\bin\TestUtils.DeviceTests\Release\net10.0-windows10.0.19041.0\Microsoft.Maui.TestUtils.DeviceTests.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Controls.Xaml -> D:\a\1\s\artifacts\bin\Controls.Xaml\Release\net10.0-windows10.0.19041.0\Microsoft.Maui.Controls.Xaml.dll
TestUtils.DeviceTests.Runners -> D:\a\1\s\artifacts\bin\TestUtils.DeviceTests.Runners\Release\net10.0-windows10.0.19041.0\Microsoft.Maui.TestUtils.DeviceTests.Runners.dll
Controls.Maps -> D:\a\1\s\artifacts\bin\Controls.Maps\Release\net10.0-windows10.0.19041.0\Microsoft.Maui.Controls.Maps.dll
Core.DeviceTests.Shared -> D:\a\1\s\artifacts\bin\Core.DeviceTests.Shared\Release\net10.0-windows10.0.19041.0\Microsoft.Maui.DeviceTests.Shared.dll
TestUtils.DeviceTests.Runners.SourceGen -> D:\a\1\s\artifacts\bin\TestUtils.DeviceTests.Runners.SourceGen\Release\netstandard2.0\Microsoft.Maui.TestUtils.DeviceTests.Runners.SourceGen.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Graphics -> D:\a\1\s\artifacts\bin\Graphics\Release\net10.0-windows10.0.19041.0\Microsoft.Maui.Graphics.dll
Controls.DeviceTests -> D:\a\1\s\artifacts\bin\Controls.DeviceTests\Release\net10.0-windows10.0.19041.0\win-x64\Microsoft.Maui.Controls.DeviceTests.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:04:57.62
Test run for D:\a\1\s\artifacts\bin\Controls.DeviceTests\Release\net10.0-windows10.0.19041.0\win-x64\Microsoft.Maui.Controls.DeviceTests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (x64)
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
Testhost process for source(s) 'D:\a\1\s\artifacts\bin\Controls.DeviceTests\Release\net10.0-windows10.0.19041.0\win-x64\Microsoft.Maui.Controls.DeviceTests.dll' exited with error: Unhandled exception. System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.TestPlatform.CoreUtilities, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.
File name: 'Microsoft.TestPlatform.CoreUtilities, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
at Microsoft.VisualStudio.TestPlatform.TestHost.Program.Main(String[] args) in /_/src/vstest/src/testhost.x86/Program.cs:line 41
. Please check the diagnostic logs for more information.
Results File: D:\a\1\s\artifacts\log\TestResults.trx
Test Run Aborted.
Tests completed with exit code: 1
🟢 With fix — 📱 LayoutTests (LayoutPanelCreatesMauiLayoutAutomationPeer, LayoutPanelAutomationPeerControlTypeIsPane, LayoutPanelClassNameReflectsCrossPlatformType, LayoutPanelWithAutomationIdIsExposedInTree, LayoutPanelAutomationPeerIsNotKeyboardFocusable, LayoutPanelAutomationPeerUpdatesWhenAutomationIdChangesAtRuntime): FAIL ❌ · 217s
Determining projects to restore...
Restored D:\a\1\s\src\Graphics\src\Graphics\Graphics.csproj (in 663 ms).
Restored D:\a\1\s\src\Core\maps\src\Maps.csproj (in 813 ms).
Restored D:\a\1\s\src\Graphics\src\Graphics.Win2D\Graphics.Win2D.csproj (in 15 ms).
Restored D:\a\1\s\src\Essentials\src\Essentials.csproj (in 46 ms).
Restored D:\a\1\s\src\Core\src\Core.csproj (in 132 ms).
Restored D:\a\1\s\src\Controls\src\Xaml\Controls.Xaml.csproj (in 92 ms).
Restored D:\a\1\s\src\Controls\src\Xaml.Design\Controls.Xaml.Design.csproj (in 14 ms).
Restored D:\a\1\s\src\Controls\src\Core.Design\Controls.Core.Design.csproj (in 4 ms).
Restored D:\a\1\s\src\Controls\src\BindingSourceGen\Controls.BindingSourceGen.csproj (in 31 ms).
Restored D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj (in 70 ms).
Restored D:\a\1\s\src\Controls\Maps\src\Controls.Maps.csproj (in 68 ms).
5 of 16 projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Graphics -> D:\a\1\s\artifacts\bin\Graphics\Release\net10.0-windows10.0.19041.0\Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Essentials -> D:\a\1\s\artifacts\bin\Essentials\Release\net10.0-windows10.0.19041.0\Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Graphics.Win2D -> D:\a\1\s\artifacts\bin\Graphics.Win2D\Release\net10.0-windows10.0.19041.0\Microsoft.Maui.Graphics.Win2D.WinUI.Desktop.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Core -> D:\a\1\s\artifacts\bin\Core\Release\net10.0-windows10.0.19041.0\Microsoft.Maui.dll
Controls.BindingSourceGen -> D:\a\1\s\artifacts\bin\Controls.BindingSourceGen\Release\netstandard2.0\Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Maps -> D:\a\1\s\artifacts\bin\Maps\Release\net10.0-windows10.0.19041.0\Microsoft.Maui.Maps.dll
TestUtils.DeviceTests -> D:\a\1\s\artifacts\bin\TestUtils.DeviceTests\Release\net10.0-windows10.0.19041.0\Microsoft.Maui.TestUtils.DeviceTests.dll
Controls.Core -> D:\a\1\s\artifacts\bin\Controls.Core\Release\net10.0-windows10.0.19041.0\Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Controls.Maps -> D:\a\1\s\artifacts\bin\Controls.Maps\Release\net10.0-windows10.0.19041.0\Microsoft.Maui.Controls.Maps.dll
Controls.Xaml -> D:\a\1\s\artifacts\bin\Controls.Xaml\Release\net10.0-windows10.0.19041.0\Microsoft.Maui.Controls.Xaml.dll
TestUtils.DeviceTests.Runners -> D:\a\1\s\artifacts\bin\TestUtils.DeviceTests.Runners\Release\net10.0-windows10.0.19041.0\Microsoft.Maui.TestUtils.DeviceTests.Runners.dll
Core.DeviceTests.Shared -> D:\a\1\s\artifacts\bin\Core.DeviceTests.Shared\Release\net10.0-windows10.0.19041.0\Microsoft.Maui.DeviceTests.Shared.dll
TestUtils.DeviceTests.Runners.SourceGen -> D:\a\1\s\artifacts\bin\TestUtils.DeviceTests.Runners.SourceGen\Release\netstandard2.0\Microsoft.Maui.TestUtils.DeviceTests.Runners.SourceGen.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Graphics -> D:\a\1\s\artifacts\bin\Graphics\Release\net10.0-windows10.0.19041.0\Microsoft.Maui.Graphics.dll
Controls.DeviceTests -> D:\a\1\s\artifacts\bin\Controls.DeviceTests\Release\net10.0-windows10.0.19041.0\win-x64\Microsoft.Maui.Controls.DeviceTests.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:03:24.83
Test run for D:\a\1\s\artifacts\bin\Controls.DeviceTests\Release\net10.0-windows10.0.19041.0\win-x64\Microsoft.Maui.Controls.DeviceTests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (x64)
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
Testhost process for source(s) 'D:\a\1\s\artifacts\bin\Controls.DeviceTests\Release\net10.0-windows10.0.19041.0\win-x64\Microsoft.Maui.Controls.DeviceTests.dll' exited with error: Unhandled exception. System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.TestPlatform.CoreUtilities, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.
File name: 'Microsoft.TestPlatform.CoreUtilities, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
at Microsoft.VisualStudio.TestPlatform.TestHost.Program.Main(String[] args) in /_/src/vstest/src/testhost.x86/Program.cs:line 41
. Please check the diagnostic logs for more information.
WARNING: Overwriting results file: D:\a\1\s\artifacts\log\TestResults.trx
Results File: D:\a\1\s\artifacts\log\TestResults.trx
Test Run Aborted.
Tests completed with exit code: 1
🔴 Without fix — 🖥️ Issue4715: FAIL ✅ · 597s
Determining projects to restore...
Restored D:\a\1\s\src\Controls\src\Xaml.Design\Controls.Xaml.Design.csproj (in 588 ms).
Restored D:\a\1\s\src\Controls\src\Core.Design\Controls.Core.Design.csproj (in 6 ms).
Restored D:\a\1\s\src\Controls\src\BindingSourceGen\Controls.BindingSourceGen.csproj (in 33 ms).
Restored D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj (in 844 ms).
Restored D:\a\1\s\src\Controls\Maps\src\Controls.Maps.csproj (in 158 ms).
Restored D:\a\1\s\src\Graphics\src\Graphics.Win2D\Graphics.Win2D.csproj (in 32 ms).
Restored D:\a\1\s\src\Graphics\src\Graphics\Graphics.csproj (in 45 ms).
Restored D:\a\1\s\src\Essentials\src\Essentials.csproj (in 55 ms).
Restored D:\a\1\s\src\Core\src\Core.csproj (in 109 ms).
Restored D:\a\1\s\src\Core\maps\src\Maps.csproj (in 78 ms).
Restored D:\a\1\s\src\Controls\src\Xaml\Controls.Xaml.csproj (in 49 ms).
3 of 14 projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Graphics -> D:\a\1\s\artifacts\bin\Graphics\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Graphics.Win2D -> D:\a\1\s\artifacts\bin\Graphics.Win2D\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Graphics.Win2D.WinUI.Desktop.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Essentials -> D:\a\1\s\artifacts\bin\Essentials\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Core -> D:\a\1\s\artifacts\bin\Core\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.dll
Controls.BindingSourceGen -> D:\a\1\s\artifacts\bin\Controls.BindingSourceGen\Debug\netstandard2.0\Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Maps -> D:\a\1\s\artifacts\bin\Maps\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Maps.dll
Controls.Core -> D:\a\1\s\artifacts\bin\Controls.Core\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Controls.Foldable -> D:\a\1\s\artifacts\bin\Controls.Foldable\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Controls.Foldable.dll
Controls.Xaml -> D:\a\1\s\artifacts\bin\Controls.Xaml\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Controls.Xaml.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Microsoft.AspNetCore.Components.WebView.Maui -> D:\a\1\s\artifacts\bin\Microsoft.AspNetCore.Components.WebView.Maui\Debug\net10.0-windows10.0.19041.0\Microsoft.AspNetCore.Components.WebView.Maui.dll
Controls.Maps -> D:\a\1\s\artifacts\bin\Controls.Maps\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Controls.Maps.dll
Controls.TestCases.HostApp -> D:\a\1\s\artifacts\bin\Controls.TestCases.HostApp\Debug\net10.0-windows10.0.19041.0\win-x64\Controls.TestCases.HostApp.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:06:03.43
Determining projects to restore...
All projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Graphics -> D:\a\1\s\artifacts\bin\Graphics\Debug\net10.0\Microsoft.Maui.Graphics.dll
Controls.CustomAttributes -> D:\a\1\s\artifacts\bin\Controls.CustomAttributes\Debug\net10.0\Controls.CustomAttributes.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Essentials -> D:\a\1\s\artifacts\bin\Essentials\Debug\net10.0\Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Core -> D:\a\1\s\artifacts\bin\Core\Debug\net10.0\Microsoft.Maui.dll
Controls.Core.Design -> D:\a\1\s\artifacts\bin\Controls.Core.Design\Debug\net472\Microsoft.Maui.Controls.DesignTools.dll
Controls.BindingSourceGen -> D:\a\1\s\artifacts\bin\Controls.BindingSourceGen\Debug\netstandard2.0\Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Controls.Core -> D:\a\1\s\artifacts\bin\Controls.Core\Debug\net10.0\Microsoft.Maui.Controls.dll
UITest.Core -> D:\a\1\s\artifacts\bin\UITest.Core\Debug\net10.0\UITest.Core.dll
UITest.Appium -> D:\a\1\s\artifacts\bin\UITest.Appium\Debug\net10.0\UITest.Appium.dll
UITest.NUnit -> D:\a\1\s\artifacts\bin\UITest.NUnit\Debug\net10.0\UITest.NUnit.dll
VisualTestUtils -> D:\a\1\s\artifacts\bin\VisualTestUtils\Debug\netstandard2.0\VisualTestUtils.dll
VisualTestUtils.MagickNet -> D:\a\1\s\artifacts\bin\VisualTestUtils.MagickNet\Debug\netstandard2.0\VisualTestUtils.MagickNet.dll
UITest.Analyzers -> D:\a\1\s\artifacts\bin\UITest.Analyzers\Debug\netstandard2.0\UITest.Analyzers.dll
Controls.TestCases.WinUI.Tests -> D:\a\1\s\artifacts\bin\Controls.TestCases.WinUI.Tests\Debug\net10.0\Controls.TestCases.WinUI.Tests.dll
Test run for D:\a\1\s\artifacts\bin\Controls.TestCases.WinUI.Tests\Debug\net10.0\Controls.TestCases.WinUI.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (x64)
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in D:\a\1\s\artifacts\bin\Controls.TestCases.WinUI.Tests\Debug\net10.0\Controls.TestCases.WinUI.Tests.dll
NUnit3TestExecutor discovered 7 of 7 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 5/21/2026 8:56:45 PM FixtureSetup for Issue4715(Windows)
>>>>> 5/21/2026 8:56:53 PM AbsoluteLayoutWithAutomationIdIsFoundByAppium Start
>>>>> 5/21/2026 8:57:10 PM AbsoluteLayoutWithAutomationIdIsFoundByAppium Stop
>>>>> 5/21/2026 8:57:11 PM Log types:
Failed AbsoluteLayoutWithAutomationIdIsFoundByAppium [18 s]
Error Message:
System.TimeoutException : Timed out waiting for element...
Stack Trace:
at UITest.Appium.HelperExtensions.Wait(Func`1 query, Func`2 satisfactory, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2757
at UITest.Appium.HelperExtensions.WaitForAtLeastOne(Func`1 query, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2784
at UITest.Appium.HelperExtensions.WaitForElement(IApp app, String marked, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency, Nullable`1 postTimeout) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 793
at Microsoft.Maui.TestCases.Tests.Issues.Issue4715.AbsoluteLayoutWithAutomationIdIsFoundByAppium() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue4715.cs:line 60
at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
>>>>> 5/21/2026 8:57:12 PM AnonymousLayoutWithoutAutomationIdIsNotFoundByAppium Start
>>>>> 5/21/2026 8:57:12 PM AnonymousLayoutWithoutAutomationIdIsNotFoundByAppium Stop
>>>>> 5/21/2026 8:57:12 PM FlexLayoutWithAutomationIdIsFoundByAppium Start
Passed AnonymousLayoutWithoutAutomationIdIsNotFoundByAppium [605 ms]
>>>>> 5/21/2026 8:57:28 PM FlexLayoutWithAutomationIdIsFoundByAppium Stop
>>>>> 5/21/2026 8:57:29 PM Log types:
Failed FlexLayoutWithAutomationIdIsFoundByAppium [16 s]
Error Message:
System.TimeoutException : Timed out waiting for element...
Stack Trace:
at UITest.Appium.HelperExtensions.Wait(Func`1 query, Func`2 satisfactory, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2757
at UITest.Appium.HelperExtensions.WaitForAtLeastOne(Func`1 query, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2784
at UITest.Appium.HelperExtensions.WaitForElement(IApp app, String marked, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency, Nullable`1 postTimeout) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 793
at Microsoft.Maui.TestCases.Tests.Issues.Issue4715.FlexLayoutWithAutomationIdIsFoundByAppium() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue4715.cs:line 50
at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
>>>>> 5/21/2026 8:57:29 PM GridWithAutomationIdIsFoundByAppium Start
>>>>> 5/21/2026 8:57:45 PM GridWithAutomationIdIsFoundByAppium Stop
>>>>> 5/21/2026 8:57:45 PM Log types:
Failed GridWithAutomationIdIsFoundByAppium [16 s]
Error Message:
System.TimeoutException : Timed out waiting for element...
Stack Trace:
at UITest.Appium.HelperExtensions.Wait(Func`1 query, Func`2 satisfactory, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2757
at UITest.Appium.HelperExtensions.WaitForAtLeastOne(Func`1 query, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2784
at UITest.Appium.HelperExtensions.WaitForElement(IApp app, String marked, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency, Nullable`1 postTimeout) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 793
at Microsoft.Maui.TestCases.Tests.Issues.Issue4715.GridWithAutomationIdIsFoundByAppium() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue4715.cs:line 20
at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
>>>>> 5/21/2026 8:57:46 PM HorizontalStackLayoutWithAutomationIdIsFoundByAppium Start
>>>>> 5/21/2026 8:58:02 PM HorizontalStackLayoutWithAutomationIdIsFoundByAppium Stop
>>>>> 5/21/2026 8:58:02 PM Log types:
Failed HorizontalStackLayoutWithAutomationIdIsFoundByAppium [16 s]
Error Message:
System.TimeoutException : Timed out waiting for element...
Stack Trace:
at UITest.Appium.HelperExtensions.Wait(Func`1 query, Func`2 satisfactory, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2757
at UITest.Appium.HelperExtensions.WaitForAtLeastOne(Func`1 query, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2784
at UITest.Appium.HelperExtensions.WaitForElement(IApp app, String marked, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency, Nullable`1 postTimeout) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 793
at Microsoft.Maui.TestCases.Tests.Issues.Issue4715.HorizontalStackLayoutWithAutomationIdIsFoundByAppium() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue4715.cs:line 40
at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
>>>>> 5/21/2026 8:58:02 PM NestedOuterLayoutWithAutomationIdIsFoundByAppium Start
>>>>> 5/21/2026 8:58:18 PM NestedOuterLayoutWithAutomationIdIsFoundByAppium Stop
>>>>> 5/21/2026 8:58:19 PM Log types:
Failed NestedOuterLayoutWithAutomationIdIsFoundByAppium [16 s]
Error Message:
System.TimeoutException : Timed out waiting for element...
Stack Trace:
at UITest.Appium.HelperExtensions.Wait(Func`1 query, Func`2 satisfactory, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2757
at UITest.Appium.HelperExtensions.WaitForAtLeastOne(Func`1 query, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2784
at UITest.Appium.HelperExtensions.WaitForElement(IApp app, String marked, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency, Nullable`1 postTimeout) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 793
at Microsoft.Maui.TestCases.Tests.Issues.Issue4715.NestedOuterLayoutWithAutomationIdIsFoundByAppium() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue4715.cs:line 70
at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
>>>>> 5/21/2026 8:58:19 PM VerticalStackLayoutWithAutomationIdIsFoundByAppium Start
>>>>> 5/21/2026 8:58:35 PM VerticalStackLayoutWithAutomationIdIsFoundByAppium Stop
>>>>> 5/21/2026 8:58:35 PM Log types:
Failed VerticalStackLayoutWithAutomationIdIsFoundByAppium [16 s]
Error Message:
System.TimeoutException : Timed out waiting for element...
Stack Trace:
at UITest.Appium.HelperExtensions.Wait(Func`1 query, Func`2 satisfactory, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2757
at UITest.Appium.HelperExtensions.WaitForAtLeastOne(Func`1 query, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2784
at UITest.Appium.HelperExtensions.WaitForElement(IApp app, String marked, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency, Nullable`1 postTimeout) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 793
at Microsoft.Maui.TestCases.Tests.Issues.Issue4715.VerticalStackLayoutWithAutomationIdIsFoundByAppium() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue4715.cs:line 30
at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
NUnit Adapter 4.5.0.0: Test execution complete
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.11] Discovering: Controls.TestCases.WinUI.Tests
[xUnit.net 00:00:00.32] Discovered: Controls.TestCases.WinUI.Tests
Results File: D:\a\1\s\CustomAgentLogsTmp\UITests\TestResults\Issue4715.trx
Total tests: 7
Passed: 1
Failed: 6
Test Run Failed.
Total time: 2.0949 Minutes
>>> TRX_RESULT_FILE: D:\a\1\s\CustomAgentLogsTmp\UITests\TestResults\Issue4715.trx
🟢 With fix — 🖥️ Issue4715: PASS ✅ · 503s
Determining projects to restore...
Restored D:\a\1\s\src\Graphics\src\Graphics.Win2D\Graphics.Win2D.csproj (in 596 ms).
Restored D:\a\1\s\src\Graphics\src\Graphics\Graphics.csproj (in 596 ms).
Restored D:\a\1\s\src\Essentials\src\Essentials.csproj (in 104 ms).
Restored D:\a\1\s\src\Core\src\Core.csproj (in 240 ms).
Restored D:\a\1\s\src\Core\maps\src\Maps.csproj (in 181 ms).
Restored D:\a\1\s\src\Controls\src\Xaml.Design\Controls.Xaml.Design.csproj (in 10 ms).
Restored D:\a\1\s\src\Controls\src\Xaml\Controls.Xaml.csproj (in 68 ms).
Restored D:\a\1\s\src\Controls\src\Core.Design\Controls.Core.Design.csproj (in 3 ms).
Restored D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj (in 59 ms).
Restored D:\a\1\s\src\Controls\src\BindingSourceGen\Controls.BindingSourceGen.csproj (in 22 ms).
Restored D:\a\1\s\src\Controls\Maps\src\Controls.Maps.csproj (in 63 ms).
3 of 14 projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Graphics -> D:\a\1\s\artifacts\bin\Graphics\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Essentials -> D:\a\1\s\artifacts\bin\Essentials\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Graphics.Win2D -> D:\a\1\s\artifacts\bin\Graphics.Win2D\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Graphics.Win2D.WinUI.Desktop.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Core -> D:\a\1\s\artifacts\bin\Core\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.dll
Controls.BindingSourceGen -> D:\a\1\s\artifacts\bin\Controls.BindingSourceGen\Debug\netstandard2.0\Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Controls.Core -> D:\a\1\s\artifacts\bin\Controls.Core\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Controls.Foldable -> D:\a\1\s\artifacts\bin\Controls.Foldable\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Controls.Foldable.dll
Microsoft.AspNetCore.Components.WebView.Maui -> D:\a\1\s\artifacts\bin\Microsoft.AspNetCore.Components.WebView.Maui\Debug\net10.0-windows10.0.19041.0\Microsoft.AspNetCore.Components.WebView.Maui.dll
Controls.Xaml -> D:\a\1\s\artifacts\bin\Controls.Xaml\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Controls.Xaml.dll
Maps -> D:\a\1\s\artifacts\bin\Maps\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Maps.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Controls.Maps -> D:\a\1\s\artifacts\bin\Controls.Maps\Debug\net10.0-windows10.0.19041.0\Microsoft.Maui.Controls.Maps.dll
Controls.TestCases.HostApp -> D:\a\1\s\artifacts\bin\Controls.TestCases.HostApp\Debug\net10.0-windows10.0.19041.0\win-x64\Controls.TestCases.HostApp.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:06:07.78
Determining projects to restore...
All projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Graphics -> D:\a\1\s\artifacts\bin\Graphics\Debug\net10.0\Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Essentials -> D:\a\1\s\artifacts\bin\Essentials\Debug\net10.0\Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Controls.CustomAttributes -> D:\a\1\s\artifacts\bin\Controls.CustomAttributes\Debug\net10.0\Controls.CustomAttributes.dll
Core -> D:\a\1\s\artifacts\bin\Core\Debug\net10.0\Microsoft.Maui.dll
Controls.Core.Design -> D:\a\1\s\artifacts\bin\Controls.Core.Design\Debug\net472\Microsoft.Maui.Controls.DesignTools.dll
Controls.BindingSourceGen -> D:\a\1\s\artifacts\bin\Controls.BindingSourceGen\Debug\netstandard2.0\Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14162521
Controls.Core -> D:\a\1\s\artifacts\bin\Controls.Core\Debug\net10.0\Microsoft.Maui.Controls.dll
VisualTestUtils -> D:\a\1\s\artifacts\bin\VisualTestUtils\Debug\netstandard2.0\VisualTestUtils.dll
UITest.Core -> D:\a\1\s\artifacts\bin\UITest.Core\Debug\net10.0\UITest.Core.dll
VisualTestUtils.MagickNet -> D:\a\1\s\artifacts\bin\VisualTestUtils.MagickNet\Debug\netstandard2.0\VisualTestUtils.MagickNet.dll
UITest.NUnit -> D:\a\1\s\artifacts\bin\UITest.NUnit\Debug\net10.0\UITest.NUnit.dll
UITest.Appium -> D:\a\1\s\artifacts\bin\UITest.Appium\Debug\net10.0\UITest.Appium.dll
UITest.Analyzers -> D:\a\1\s\artifacts\bin\UITest.Analyzers\Debug\netstandard2.0\UITest.Analyzers.dll
Controls.TestCases.WinUI.Tests -> D:\a\1\s\artifacts\bin\Controls.TestCases.WinUI.Tests\Debug\net10.0\Controls.TestCases.WinUI.Tests.dll
Test run for D:\a\1\s\artifacts\bin\Controls.TestCases.WinUI.Tests\Debug\net10.0\Controls.TestCases.WinUI.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (x64)
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in D:\a\1\s\artifacts\bin\Controls.TestCases.WinUI.Tests\Debug\net10.0\Controls.TestCases.WinUI.Tests.dll
NUnit3TestExecutor discovered 7 of 7 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 5/21/2026 9:10:22 PM FixtureSetup for Issue4715(Windows)
>>>>> 5/21/2026 9:10:31 PM AbsoluteLayoutWithAutomationIdIsFoundByAppium Start
>>>>> 5/21/2026 9:10:32 PM AbsoluteLayoutWithAutomationIdIsFoundByAppium Stop
>>>>> 5/21/2026 9:10:32 PM AnonymousLayoutWithoutAutomationIdIsNotFoundByAppium Start
Passed AbsoluteLayoutWithAutomationIdIsFoundByAppium [1 s]
>>>>> 5/21/2026 9:10:33 PM AnonymousLayoutWithoutAutomationIdIsNotFoundByAppium Stop
>>>>> 5/21/2026 9:10:33 PM FlexLayoutWithAutomationIdIsFoundByAppium Start
>>>>> 5/21/2026 9:10:33 PM FlexLayoutWithAutomationIdIsFoundByAppium Stop
>>>>> 5/21/2026 9:10:33 PM GridWithAutomationIdIsFoundByAppium Start
Passed AnonymousLayoutWithoutAutomationIdIsNotFoundByAppium [594 ms]
Passed FlexLayoutWithAutomationIdIsFoundByAppium [762 ms]
>>>>> 5/21/2026 9:10:34 PM GridWithAutomationIdIsFoundByAppium Stop
>>>>> 5/21/2026 9:10:34 PM HorizontalStackLayoutWithAutomationIdIsFoundByAppium Start
>>>>> 5/21/2026 9:10:35 PM HorizontalStackLayoutWithAutomationIdIsFoundByAppium Stop
>>>>> 5/21/2026 9:10:35 PM NestedOuterLayoutWithAutomationIdIsFoundByAppium Start
Passed GridWithAutomationIdIsFoundByAppium [715 ms]
Passed HorizontalStackLayoutWithAutomationIdIsFoundByAppium [693 ms]
>>>>> 5/21/2026 9:10:35 PM NestedOuterLayoutWithAutomationIdIsFoundByAppium Stop
>>>>> 5/21/2026 9:10:35 PM VerticalStackLayoutWithAutomationIdIsFoundByAppium Start
>>>>> 5/21/2026 9:10:36 PM VerticalStackLayoutWithAutomationIdIsFoundByAppium Stop
Passed NestedOuterLayoutWithAutomationIdIsFoundByAppium [691 ms]
Passed VerticalStackLayoutWithAutomationIdIsFoundByAppium [662 ms]
NUnit Adapter 4.5.0.0: Test execution complete
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.12] Discovering: Controls.TestCases.WinUI.Tests
[xUnit.net 00:00:00.34] Discovered: Controls.TestCases.WinUI.Tests
Results File: D:\a\1\s\CustomAgentLogsTmp\UITests\TestResults\Issue4715.trx
Test Run Successful.
Total tests: 7
Passed: 7
Total time: 28.8925 Seconds
>>> TRX_RESULT_FILE: D:\a\1\s\CustomAgentLogsTmp\UITests\TestResults\Issue4715.trx
⚠️ Failure Details
- ❌ LayoutTests (LayoutPanelCreatesMauiLayoutAutomationPeer, LayoutPanelAutomationPeerControlTypeIsPane, LayoutPanelClassNameReflectsCrossPlatformType, LayoutPanelWithAutomationIdIsExposedInTree, LayoutPanelAutomationPeerIsNotKeyboardFocusable, LayoutPanelAutomationPeerUpdatesWhenAutomationIdChangesAtRuntime) FAILED with fix (should pass)
📁 Fix files reverted (4 files)
.gitignoreeng/pipelines/ci-copilot.ymlsrc/Core/src/Platform/Windows/LayoutPanel.cssrc/Core/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt
New files (not reverted):
src/Core/src/Platform/Windows/MauiLayoutAutomationPeer.cs
🧪 UI Tests — Layout,ViewBaseTests
Detected UI test categories: Layout,ViewBaseTests
✅ Deep UI tests — 305 passed, 0 failed across 2 categories on platform-pool agent (replaces in-process counts above).
🧪 UI Test Execution Results (deep, platform pool)
| Category | Tests | Snapshot diffs |
|---|---|---|
Layout |
190/194 ✓ | — |
ViewBaseTests |
115/115 ✓ | — |
📎 Download drop-deep-uitests artifact (TRX + snapshot diffs) |
🔍 Regression Cross-Reference
🔍 Regression Cross-Reference
🟢 No regression risks detected. No labeled bug-fix PRs in the last 6 months touched the modified files.
🔍 Pre-Flight — Context & Validation
Pre-Flight Context — PR #35562
Summary
PR #35562 ("[Windows] Add Automation Id support for Layouts") fixes part of issue #4715: layout containers (Grid, VerticalStackLayout, HorizontalStackLayout, FlexLayout, AbsoluteLayout, StackLayout) on Windows are invisible to the UI Automation (UIA) tree, so an AutomationId set on them cannot be located by Appium, UI Verify, screen readers, etc.
Issue #4715
- Title: "[Windows] AutomationId does not work for ContentView, Layouts and controls that inherit them"
- Reported in 2022 by partner (Syncfusion / GeorgeDarakchiev). Marked
t/bug,platform/windows,area-layout,t/a11y,partner, milestoneBacklog. - Root cause on WinUI: A bare
Panel(and subclasses without a customAutomationPeer) is not exposed in the Content View of the UIA tree.AutomationProperties.AutomationIdis set on the panel, but consumers walking the Content tree never see it because the default peer reportsIsContentElement = false. - The issue text mentions Border / ContentView as well as Layouts. The PR addresses Layouts only (LayoutPanel).
ContentPanel(which backs ContentView / Border content) is not modified by the PR even though it has the same problem.
PR Approach (current fix)
Modifies src/Core/src/Platform/Windows/LayoutPanel.cs:
- Overrides
OnCreateAutomationPeer()to return a new internalMauiLayoutAutomationPeer. - New
MauiLayoutAutomationPeer : FrameworkElementAutomationPeeroverrides:GetClassNameCore()→ cross-platform layout type name ("Grid","VerticalStackLayout", …) or"Panel"fallback.GetAutomationControlTypeCore()→AutomationControlType.Pane.IsKeyboardFocusableCore()→false.IsControlElementCore()→true(always in Control View — lets Narrator readSemanticProperties.Description).IsContentElementCore()→trueonly whenAutomationProperties.GetAutomationId(panel)is non-empty.
- Adds
override Microsoft.Maui.Platform.LayoutPanel.OnCreateAutomationPeer()toPublicAPI.Unshipped.txt. - Adds DeviceTests (xUnit) in
LayoutTests.Windows.csand a UI test + HostApp page (Issue4715).
Gate result (already run, see gate/content.md)
- ❌ Gate failed. The verification harness flagged "Regression in another test" but inspection of the logs shows:
- 🖥️ Issue4715 UI test: ✅ FAIL → ✅ PASS (the PR fix actually works for the user-facing scenario).
- 📱 LayoutTests DeviceTests: FAIL both without and with the fix — but the failure is a testhost infrastructure issue, not a logical regression:
Testhost process exited with error: Unhandled exception. System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.TestPlatform.CoreUtilities, Version=15.0.0.0, ...' - So device tests cannot actually execute on this environment regardless of the fix. The "regression" verdict is a false positive caused by environment, not a real failure introduced by the PR.
Regression / UI-tests context
- Regression cross-reference: 🟢 no recent bug-fix PRs touched these files.
- UI-test sweep (
Layout+ViewBaseTests):Layout190/194 passed including all 7 new Issue4715 tests. The one ViewBaseTests failure (BoxView_ClipWithRotation) is unrelated (Appium timeout on a rotation/clip test that has no overlap with this PR's surface).
Files touched by the PR
| File | Change |
|---|---|
src/Core/src/Platform/Windows/LayoutPanel.cs |
+6 — adds OnCreateAutomationPeer override |
src/Core/src/Platform/Windows/MauiLayoutAutomationPeer.cs |
NEW (+53) — custom peer |
src/Core/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt |
+1 — new public API entry |
src/Controls/tests/DeviceTests/Elements/Layout/LayoutTests.Windows.cs |
+133 DeviceTests |
src/Controls/tests/TestCases.HostApp/Issues/Issue4715.cs |
NEW HostApp page |
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue4715.cs |
NEW UI tests |
Alternative fix dimensions worth exploring
- Scope — the PR fixes only
LayoutPanel. The original issue also affectsContentPanel(ContentView / Border). A broader fix atMauiPanelbase level (or duplicated onContentPanel) would resolve more of the originally-reported symptoms. - Mechanism — instead of a full custom
AutomationPeer, a much smaller fix is to setAutomationProperties.AccessibilityView = Contenton the panel whenAutomationIdis non-empty (touchUpdateAutomationIdinViewExtensions.Windows.cs). This avoids a new type and a new public API entry. - Class-name strategy — the PR exposes the MAUI type name as
ClassName. An alternative is to return the existing default ("Panel") and only overrideIsContentElement/IsControlElement. Less behavioral surface = lower regression risk for any tooling that already grepped forPanel. - Always-on vs. AutomationId-gated — PR's
IsControlElementCore => truealways makes layouts show in the Control view, which slightly changes Narrator behavior for anonymous layouts. An alternative gates BOTHIsControlElementandIsContentElementonHasAutomationId/HasSemanticDescription, leaving anonymous layouts invisible (closer to pre-PR behavior, narrower blast radius).
These dimensions inform the try-fix candidates below.
🔧 Fix — Analysis & Comparison
Try-Fix Aggregate — PR #35562
Overview
The PR fixes the Layouts half of issue #4715 by introducing a custom
MauiLayoutAutomationPeer on LayoutPanel (Windows). The gate confirmed
the user-facing UI test transitions FAIL → PASS with the PR's fix; the
gate's overall FAIL verdict came from a testhost infrastructure problem
(FileNotFoundException: Microsoft.TestPlatform.CoreUtilities) hitting the
DeviceTests run identically with and without the fix — not a real
regression introduced by the PR.
Given that the PR's mechanism works for the user-facing scenario, three
meaningfully differentiated alternative approaches were generated to
explore the design space across two axes:
- Mechanism: custom AutomationPeer (PR's approach) vs. attached property (
AccessibilityView). - Scope: LayoutPanel only (PR) vs. broader (also ContentPanel) vs. behavior-policy variation.
Candidates
try-fix-1 — Minimal AccessibilityView Approach (strongest candidate)
- Mechanism: WinUI attached property —
AutomationProperties.AccessibilityView = Content. - Scope: every
FrameworkElement(via sharedUpdateAutomationIdchokepoint). - Code added: ~4 LOC, no new file, no new public API entry.
- Resolves: Layouts + ContentView + Border (full issue [Windows] AutomationId does not work for ContentView, Layouts and controls that inherit them #4715, not just half).
- Trade-off: drops PR's optional class-name / control-type customization. PR's DeviceTests asserting on peer type / class name would need to be rewritten.
Full report: try-fix-1/content.md.
try-fix-2 — Broader Scope: Same Mechanism, Cover ContentPanel Too
- Mechanism: custom AutomationPeer (same as PR).
- Scope: LayoutPanel + ContentPanel, sharing one
MauiPanelAutomationPeer. - Code added: same as PR + small ContentPanel override + 1 extra public API entry.
- Resolves: full issue [Windows] AutomationId does not work for ContentView, Layouts and controls that inherit them #4715 while preserving PR's class-name and control-type semantics.
- Trade-off: larger blast radius (every ContentView gets a new peer); needs verification that this doesn't disturb Border's outer element.
Full report: try-fix-2/content.md.
try-fix-3 — Conservative Behavior Policy
- Mechanism: custom AutomationPeer (same as PR).
- Scope: LayoutPanel only (same as PR).
- Behavior change vs. PR: gate
IsControlElementon AutomationId/SemanticDescription (not always-on); drop class-name and control-type overrides. - Resolves: same scope as PR.
- Trade-off: anonymous layouts stay hidden from UIA (matches pre-PR baseline → lowest regression risk for screen readers); loses PR's class-name reporting.
Full report: try-fix-3/content.md.
Comparison Matrix
| Dimension | PR | try-fix-1 | try-fix-2 | try-fix-3 |
|---|---|---|---|---|
| Mechanism | AutomationPeer | AccessibilityView | AutomationPeer | AutomationPeer |
| Fixes Layouts | ✅ | ✅ | ✅ | ✅ |
| Fixes ContentView | ❌ | ✅ | ✅ | ❌ |
| Fixes Border (content) | ❌ | ✅ | ✅ | ❌ |
| New public API entries | 1 | 0 | 2 | 1 |
| New types | 1 | 0 | 1 | 1 |
| Net LOC | ~60 + tests | ~4 | ~65 + tests | ~30 (smaller than PR) |
| Anonymous-layout exposure | Control view | unchanged | Control view | unchanged |
| Class-name customization | ✅ | ❌ | ✅ | ❌ |
| PR's new DeviceTests | pass | most fail (need rewrite) | pass (rename) | 2 of 6 fail |
| Issue4715 UI test (FAIL→PASS) | ✅ | ✅ | ✅ | ✅ |
Testing Caveat
This Windows build environment has a broken DeviceTests testhost
(FileNotFoundException: Microsoft.TestPlatform.CoreUtilities — see
gate/verify-tests-fail/). The failure occurs on the head of main
itself, not because of the PR or any candidate. So no candidate can be
empirically validated via the PR's DeviceTests in this environment.
What was verified during the gate run:
- The PR's Issue4715 UI test (Appium-driven, the user-facing bug
reproduction) goes ✅ FAIL → ✅ PASS with the PR's fix. - For try-fix-1, try-fix-2, try-fix-3: by inspection of the fix mechanism
and the test's assertions (AppiumWaitForElementby AutomationId on
named layouts;WaitForNoElementon anonymous Grid), all three
candidates would satisfy the same UI test assertions identically.
Iteration / "Learn" Notes
No candidate failed in a way that produced new information to feed back
into the next candidate — the three approaches were derived a priori from
two independent design axes (mechanism × scope/policy), each exploring a
genuinely distinct hypothesis. Further candidates would be trivial
variations (e.g. different AccessibilityView enum semantics, different
opt-in predicates) and were not generated.
Recommendation
try-fix-1 is the cleanest alternative if the team is willing to
trade the PR's class-name customization for a ~93% smaller diff that
also fixes the ContentView/Border halves of issue #4715. try-fix-2
is the closest "PR + completeness" sibling — same design, broader scope.
try-fix-3 is the safest behavior-wise but solves only the same scope
as the PR with slightly less customization.
If the PR's class-name reporting is a hard requirement, try-fix-2 is
the recommended evolution of the PR. If it isn't, try-fix-1 is
strictly more elegant.
📋 Report — Final Recommendation
Comparative Report — PR #35562 Candidates
Candidates evaluated
| Candidate | Mechanism | Scope | Net LOC | Source |
|---|---|---|---|---|
pr |
Custom AutomationPeer (always-on Control view) |
LayoutPanel only |
~60 + tests | PR HEAD |
pr-plus-reviewer |
Custom AutomationPeer (metadata-gated Control view, broadened predicate) |
LayoutPanel only |
~60 + tests (test relaxed) | expert-pr-eval/content.md |
try-fix-1 |
AutomationProperties.AccessibilityView = Content attached property |
every FrameworkElement via UpdateAutomationId |
~4 | try-fix-1/content.md |
try-fix-2 |
Custom AutomationPeer (PR's policy) |
LayoutPanel and ContentPanel |
~65 + tests | try-fix-2/content.md |
try-fix-3 |
Custom AutomationPeer (metadata-gated, no class-name / control-type overrides) |
LayoutPanel only |
~30 | try-fix-3/content.md |
Test outcome (all candidates, this environment)
The Windows DeviceTests testhost is broken in this environment
(FileNotFoundException: Microsoft.TestPlatform.CoreUtilities) — fails
identically with and without the PR, on all candidates. So device
tests cannot empirically distinguish candidates.
The Appium-driven Issue4715 UI test (the user-facing reproduction from the
original bug) is the authoritative gate. By inspection of each candidate's
mechanism against the test's assertions (WaitForElement on named layouts;
WaitForNoElement on the anonymous Grid):
| Candidate | Issue4715 UI test | Notes |
|---|---|---|
pr |
✅ PASS (verified by gate) | confirmed FAIL→PASS |
pr-plus-reviewer |
✅ PASS (by inspection) | named layouts still expose AutomationId; anonymous Grid still hidden |
try-fix-1 |
✅ PASS (by inspection) | AccessibilityView=Content set on named layouts; anonymous unchanged |
try-fix-2 |
✅ PASS (by inspection) | same as pr plus ContentPanel — same UI test assertions hold |
try-fix-3 |
✅ PASS (by inspection) | metadata-gated; named layouts still in Content view |
No candidate failed a regression test. All candidates are equivalent on
test outcome in this environment.
Comparison matrix
| Dimension | pr |
pr-plus-reviewer |
try-fix-1 |
try-fix-2 |
try-fix-3 |
|---|---|---|---|---|---|
| Fixes Layouts (issue #4715 Layouts half) | ✅ | ✅ | ✅ | ✅ | ✅ |
| Fixes ContentView/Border (issue #4715 other half) | ❌ | ❌ | ✅ | ✅ | ❌ |
| Anonymous-layout Control View flooding (Narrator noise) | ❌ floods | ✅ avoided | ✅ avoided | ❌ floods | ✅ avoided |
Honors SemanticProperties.Description without AutomationId |
❌ | ✅ | ✅ (attached prop only fires for AutomationId though) | ❌ | |
| New types | 1 | 1 | 0 | 1 | 1 |
| New public API entries | 1 | 1 | 0 | 2 | 1 |
| Class-name customization preserved | ✅ | ✅ | ❌ | ✅ | ❌ |
AutomationControlType.Pane preserved |
✅ | ✅ | ❌ | ✅ | ❌ |
| PR's existing DeviceTests | pass as-is | pass after 1 test relaxation + 1 broadened assert | most fail (need rewrite) | pass after rename | 2 of 6 fail / need rewrite |
| Net code | ~60 + tests | ~60 + tests | ~4 | ~65 + tests | ~30 |
Ranking & rationale
1st — pr-plus-reviewer 🏆
The PR's mechanism, layering and public-API discipline are correct, and the
expert reviewer surfaced one concrete, real accessibility regression risk
(IsControlElementCore => true unconditional → every nested anonymous layout
joins the Control View, flooding Narrator's reading order on any moderately
nested page). pr-plus-reviewer keeps every strength of the PR — the custom
peer architecture, ClassName reflecting cross-platform type, Pane control
type, the existing UI-test coverage — and fixes that risk plus the
narrower-than-it-should-be metadata predicate (now recognises
SemanticProperties.Description, HelpText, LabeledBy). Strictly better
than pr on the accessibility dimension; equal on every other axis.
2nd — try-fix-3 (conservative behavior policy)
Same accessibility-safety improvement as pr-plus-reviewer (metadata-gated
Control view), but loses the ClassName customization and the Pane control
type. Smaller and safer, but throws away two of the PR's deliberate features
without strong justification. Two of the PR's six DeviceTests must be
removed/rewritten. Stays at the PR's narrower LayoutPanel-only scope.
3rd — try-fix-2 (broader scope, same PR policy)
Resolves the full issue #4715 (ContentView/Border) which pr and
pr-plus-reviewer don't. But it carries the same unconditional
IsControlElementCore => true accessibility regression that the expert
flagged — now amplified across ContentPanel too (which is very common in
real apps). Higher scope + worse Narrator behavior is not a great trade.
4th — try-fix-1 (AccessibilityView attached property)
Most elegant by LOC (~4 lines, no new type, no public API entry) and fixes the
broadest scope (every FrameworkElement). However it (a) drops the PR's
ClassName="Grid" reporting, (b) invalidates most of the PR's new DeviceTests,
(c) only reacts to AutomationId — a layout labelled with only
SemanticProperties.Description stays hidden. Strong runner-up if the team
ever wants to revisit the minimal mechanism, but it requires more re-test
work than the others.
5th — pr (the PR as submitted)
Works for the user-facing scenario (verified by Appium gate ✅ FAIL→PASS) and
ships solid coverage. The single material issue is the unconditional
IsControlElementCore => true — a real Narrator-UX regression risk for the
common case of deeply nested layouts. pr-plus-reviewer is a one-predicate
change on top of pr that removes the risk while keeping everything else
identical, so ranking pr-plus-reviewer above pr is straightforward.
Winner: pr-plus-reviewer
The PR's mechanism is correct and the test suite the PR added (the Appium
Issue4715 page + UI tests) is genuinely valuable. The expert review identified
one real defect and one real omission, both addressable with a
~10-line diff on top of the PR. Adopting pr-plus-reviewer preserves the PR
author's design choices and the existing Appium gate, while removing a
plausible Narrator regression that would otherwise have to be patched in a
follow-up. ContentView/Border scope (covered by try-fix-1 and try-fix-2)
is deliberately deferred — issue #4715 calls it out but the PR title scopes
to Layouts, and that broader scope is a clean follow-up PR using the same
shared peer.
MauiBot
left a comment
There was a problem hiding this comment.
Expert Review — 3 findings
See inline comments for details.
| // TODO: Make this class public in .NET11.0 | ||
| internal partial class MauiLayoutAutomationPeer : FrameworkElementAutomationPeer | ||
| { | ||
| internal MauiLayoutAutomationPeer(LayoutPanel owner) : base(owner) { } |
There was a problem hiding this comment.
[major] Windows Accessibility / Regression Prevention — The new peer is hard-coded to LayoutPanel, so the fix does not apply to ContentPanel-backed controls. ContentViewHandler.Windows.cs and BorderHandler.Windows.cs both create ContentPanel, and issue #4715 explicitly reports ContentView and Border as affected. As implemented, those controls still get the default panel peer behavior and remain unfixed. Consider making the peer accept MauiPanel and overriding OnCreateAutomationPeer() from both LayoutPanel and ContentPanel, or moving the override to a shared base if appropriate.
| protected override bool IsControlElementCore() => true; | ||
|
|
||
| // Expose in the Content View only when an AutomationId is explicitly set by the developer. | ||
| protected override bool IsContentElementCore() => HasAutomationId(); |
There was a problem hiding this comment.
[major] Accessibility / Windows Platform Specifics — IsContentElementCore() only checks AutomationId, while IsControlElementCore() above always returns true, so this bypasses MAUI's existing AutomationProperties.IsInAccessibleTree mapping to WinUI AutomationProperties.AccessibilityView. Concrete cases: a layout with AutomationId and AutomationProperties.IsInAccessibleTree="False" is still exposed, and a layout with AutomationProperties.IsInAccessibleTree="True" but no AutomationId is still not a content element. The peer should respect the native AccessibilityView value set by Element.Windows.cs instead of deriving exposure solely from AutomationId.
| App.WaitForElement("WaitForStubControl"); | ||
|
|
||
| // Anonymous Grid (no AutomationId) must NOT be found in the UIA tree | ||
| App.WaitForNoElement("Anonymous Grid"); |
There was a problem hiding this comment.
[moderate] Regression Prevention / Test Correctness — App.WaitForNoElement("Anonymous Grid") passes trivially because WaitForNoElement(string) searches by accessibility id on Windows, and no element in the test page has AutomationId = "Anonymous Grid". The anonymous grid has no AutomationId; its child label has text "Anonymous Grid (no AutomationId)". This does not verify that unnamed layout containers are excluded from the UIA tree. Add a real negative assertion using the same lookup mechanism the bug depends on, or query by text/name explicitly if that is the behavior being validated.
#35562 makes LayoutPanel always appear in the UIA Control view (and also the Content view whenever AutomationId is set). That means screen readers like Narrator and NVDA now stop on every Grid / StackLayout / ContentView in a MAUI page, which is noisy and works against WinUI's default behavior of treating layout containers as structural rather than content. AutomationId on a layout is overwhelmingly used as a UI testing hook (Appium / WinAppDriver and similar look up elements by id in the UIA raw view, which is unaffected) rather than as an accessibility landmark. So this change keeps AutomationId fully functional for UI tests while making screen-reader visibility opt-in. MauiLayoutAutomationPeer now reports IsControlElement / IsContentElement as false by default. They become true when the developer signals that the panel should participate in the accessibility tree: * AutomationProperties.IsInAccessibleTree="True" (mapped on Windows to AccessibilityView=Content) -> IsControlElement and IsContentElement both true. * SemanticProperties.Description / Hint set on the layout (mapped to AutomationProperties.Name / HelpText) -> IsControlElement true, so screen readers will announce the description. Tests updated and added in LayoutTests.Windows.cs: * AutomationId is verified via peer.GetAutomationId() directly (raw view), not via IsContentElement. * New tests cover the opt-in paths (IsInAccessibleTree and Description) and confirm AutomationId alone does not put the panel into the Control view. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
<!-- Please keep the note below for people who find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment whether this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> This pull request adds a custom automation peer to `LayoutPanel` on Windows to improve accessibility support for layout containers in .NET MAUI. The new `MauiLayoutAutomationPeer` provides more accurate class names, control types, and automation exposure for layouts, and includes comprehensive tests to validate this behavior. ### Description of Change **Accessibility improvements for layout containers:** * Added a new internal class `MauiLayoutAutomationPeer` that customizes accessibility for layout containers by overriding methods such as `GetClassNameCore`, `GetAutomationControlTypeCore`, `IsKeyboardFocusableCore`, `IsControlElementCore`, and `IsContentElementCore`. This ensures screen readers and automation tools receive accurate information about layout elements. * Overrode `OnCreateAutomationPeer()` in `LayoutPanel` to return an instance of `MauiLayoutAutomationPeer`, enabling the new accessibility behavior. [[1]](diffhunk://#diff-5aa44e4d2e39e6615cdb0384b23aa3df7323a5ad3fd2cc545a0d59c99f1fc985R16-R20) [[2]](diffhunk://#diff-c710daaba40199243111fcb8a8d5185e939c757b00785b0780d5217c8cf757e5R2) **Test coverage for layout automation:** * Added a suite of tests in `LayoutTests.Windows.cs` to verify that the correct automation peer is created, the control type is set to `Pane`, the class name reflects the cross-platform layout type, and that automation tree exposure and keyboard focusability behave as expected. Tests also cover runtime changes to `AutomationId`. **Dependency and using updates:** * Updated using directives in relevant files to include automation peer namespaces required for the new functionality. [[1]](diffhunk://#diff-453047cf9d895169547b2b8498bd8e60caa11236407c58a46687fba420e01cfeR9-R11) [[2]](diffhunk://#diff-5aa44e4d2e39e6615cdb0384b23aa3df7323a5ad3fd2cc545a0d59c99f1fc985R2) <!-- Enter description of the fix in this section --> ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes #4715 ### Tested the behavior in the following platforms - [x] Windows - [ ] Android - [ ] iOS - [ ] Mac | Before Issue Fix | After Issue Fix | |----------|----------| | <img width="1911" height="927" alt="image (9)" src="https://github.com/user-attachments/assets/21e08b36-b426-4654-ad6a-46bba853d646" /> | <img width="1911" height="927" alt="Screenshot 2026-05-19 193253" src="https://github.com/user-attachments/assets/e6c70a98-ae64-4a58-a9d5-700174c13411" />| <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. -->
<!-- Please keep the note below for people who find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment whether this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> This pull request adds a custom automation peer to `LayoutPanel` on Windows to improve accessibility support for layout containers in .NET MAUI. The new `MauiLayoutAutomationPeer` provides more accurate class names, control types, and automation exposure for layouts, and includes comprehensive tests to validate this behavior. ### Description of Change **Accessibility improvements for layout containers:** * Added a new internal class `MauiLayoutAutomationPeer` that customizes accessibility for layout containers by overriding methods such as `GetClassNameCore`, `GetAutomationControlTypeCore`, `IsKeyboardFocusableCore`, `IsControlElementCore`, and `IsContentElementCore`. This ensures screen readers and automation tools receive accurate information about layout elements. * Overrode `OnCreateAutomationPeer()` in `LayoutPanel` to return an instance of `MauiLayoutAutomationPeer`, enabling the new accessibility behavior. [[1]](diffhunk://#diff-5aa44e4d2e39e6615cdb0384b23aa3df7323a5ad3fd2cc545a0d59c99f1fc985R16-R20) [[2]](diffhunk://#diff-c710daaba40199243111fcb8a8d5185e939c757b00785b0780d5217c8cf757e5R2) **Test coverage for layout automation:** * Added a suite of tests in `LayoutTests.Windows.cs` to verify that the correct automation peer is created, the control type is set to `Pane`, the class name reflects the cross-platform layout type, and that automation tree exposure and keyboard focusability behave as expected. Tests also cover runtime changes to `AutomationId`. **Dependency and using updates:** * Updated using directives in relevant files to include automation peer namespaces required for the new functionality. [[1]](diffhunk://#diff-453047cf9d895169547b2b8498bd8e60caa11236407c58a46687fba420e01cfeR9-R11) [[2]](diffhunk://#diff-5aa44e4d2e39e6615cdb0384b23aa3df7323a5ad3fd2cc545a0d59c99f1fc985R2) <!-- Enter description of the fix in this section --> ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes #4715 ### Tested the behavior in the following platforms - [x] Windows - [ ] Android - [ ] iOS - [ ] Mac | Before Issue Fix | After Issue Fix | |----------|----------| | <img width="1911" height="927" alt="image (9)" src="https://github.com/user-attachments/assets/21e08b36-b426-4654-ad6a-46bba853d646" /> | <img width="1911" height="927" alt="Screenshot 2026-05-19 193253" src="https://github.com/user-attachments/assets/e6c70a98-ae64-4a58-a9d5-700174c13411" />| <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. --> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
#35562 makes LayoutPanel always appear in the UIA Control view (and also the Content view whenever AutomationId is set). That means screen readers like Narrator and NVDA now stop on every Grid / StackLayout / ContentView in a MAUI page, which is noisy and works against WinUI's default behavior of treating layout containers as structural rather than content. AutomationId on a layout is overwhelmingly used as a UI testing hook (Appium / WinAppDriver and similar look up elements by id in the UIA raw view, which is unaffected) rather than as an accessibility landmark. So this change keeps AutomationId fully functional for UI tests while making screen-reader visibility opt-in. MauiLayoutAutomationPeer now reports IsControlElement / IsContentElement as false by default. They become true when the developer signals that the panel should participate in the accessibility tree: * AutomationProperties.IsInAccessibleTree="True" (mapped on Windows to AccessibilityView=Content) -> IsControlElement and IsContentElement both true. * SemanticProperties.Description / Hint set on the layout (mapped to AutomationProperties.Name / HelpText) -> IsControlElement true, so screen readers will announce the description. Tests updated and added in LayoutTests.Windows.cs: * AutomationId is verified via peer.GetAutomationId() directly (raw view), not via IsContentElement. * New tests cover the opt-in paths (IsInAccessibleTree and Description) and confirm AutomationId alone does not put the panel into the Control view. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
<!-- Please keep the note below for people who find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment whether this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> This pull request adds a custom automation peer to `LayoutPanel` on Windows to improve accessibility support for layout containers in .NET MAUI. The new `MauiLayoutAutomationPeer` provides more accurate class names, control types, and automation exposure for layouts, and includes comprehensive tests to validate this behavior. ### Description of Change **Accessibility improvements for layout containers:** * Added a new internal class `MauiLayoutAutomationPeer` that customizes accessibility for layout containers by overriding methods such as `GetClassNameCore`, `GetAutomationControlTypeCore`, `IsKeyboardFocusableCore`, `IsControlElementCore`, and `IsContentElementCore`. This ensures screen readers and automation tools receive accurate information about layout elements. * Overrode `OnCreateAutomationPeer()` in `LayoutPanel` to return an instance of `MauiLayoutAutomationPeer`, enabling the new accessibility behavior. [[1]](diffhunk://#diff-5aa44e4d2e39e6615cdb0384b23aa3df7323a5ad3fd2cc545a0d59c99f1fc985R16-R20) [[2]](diffhunk://#diff-c710daaba40199243111fcb8a8d5185e939c757b00785b0780d5217c8cf757e5R2) **Test coverage for layout automation:** * Added a suite of tests in `LayoutTests.Windows.cs` to verify that the correct automation peer is created, the control type is set to `Pane`, the class name reflects the cross-platform layout type, and that automation tree exposure and keyboard focusability behave as expected. Tests also cover runtime changes to `AutomationId`. **Dependency and using updates:** * Updated using directives in relevant files to include automation peer namespaces required for the new functionality. [[1]](diffhunk://#diff-453047cf9d895169547b2b8498bd8e60caa11236407c58a46687fba420e01cfeR9-R11) [[2]](diffhunk://#diff-5aa44e4d2e39e6615cdb0384b23aa3df7323a5ad3fd2cc545a0d59c99f1fc985R2) <!-- Enter description of the fix in this section --> ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes #4715 ### Tested the behavior in the following platforms - [x] Windows - [ ] Android - [ ] iOS - [ ] Mac | Before Issue Fix | After Issue Fix | |----------|----------| | <img width="1911" height="927" alt="image (9)" src="https://github.com/user-attachments/assets/21e08b36-b426-4654-ad6a-46bba853d646" /> | <img width="1911" height="927" alt="Screenshot 2026-05-19 193253" src="https://github.com/user-attachments/assets/e6c70a98-ae64-4a58-a9d5-700174c13411" />| <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. -->
<!-- Please keep the note below for people who find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment whether this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> This pull request adds a custom automation peer to `LayoutPanel` on Windows to improve accessibility support for layout containers in .NET MAUI. The new `MauiLayoutAutomationPeer` provides more accurate class names, control types, and automation exposure for layouts, and includes comprehensive tests to validate this behavior. ### Description of Change **Accessibility improvements for layout containers:** * Added a new internal class `MauiLayoutAutomationPeer` that customizes accessibility for layout containers by overriding methods such as `GetClassNameCore`, `GetAutomationControlTypeCore`, `IsKeyboardFocusableCore`, `IsControlElementCore`, and `IsContentElementCore`. This ensures screen readers and automation tools receive accurate information about layout elements. * Overrode `OnCreateAutomationPeer()` in `LayoutPanel` to return an instance of `MauiLayoutAutomationPeer`, enabling the new accessibility behavior. [[1]](diffhunk://#diff-5aa44e4d2e39e6615cdb0384b23aa3df7323a5ad3fd2cc545a0d59c99f1fc985R16-R20) [[2]](diffhunk://#diff-c710daaba40199243111fcb8a8d5185e939c757b00785b0780d5217c8cf757e5R2) **Test coverage for layout automation:** * Added a suite of tests in `LayoutTests.Windows.cs` to verify that the correct automation peer is created, the control type is set to `Pane`, the class name reflects the cross-platform layout type, and that automation tree exposure and keyboard focusability behave as expected. Tests also cover runtime changes to `AutomationId`. **Dependency and using updates:** * Updated using directives in relevant files to include automation peer namespaces required for the new functionality. [[1]](diffhunk://#diff-453047cf9d895169547b2b8498bd8e60caa11236407c58a46687fba420e01cfeR9-R11) [[2]](diffhunk://#diff-5aa44e4d2e39e6615cdb0384b23aa3df7323a5ad3fd2cc545a0d59c99f1fc985R2) <!-- Enter description of the fix in this section --> ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes #4715 ### Tested the behavior in the following platforms - [x] Windows - [ ] Android - [ ] iOS - [ ] Mac | Before Issue Fix | After Issue Fix | |----------|----------| | <img width="1911" height="927" alt="image (9)" src="https://github.com/user-attachments/assets/21e08b36-b426-4654-ad6a-46bba853d646" /> | <img width="1911" height="927" alt="Screenshot 2026-05-19 193253" src="https://github.com/user-attachments/assets/e6c70a98-ae64-4a58-a9d5-700174c13411" />| <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. -->
Follow-up to #35562. That PR added MauiLayoutAutomationPeer so AutomationId set on a Layout is visible to UI Automation clients (Appium / WinAppDriver), but as a side effect every LayoutPanel was reported as a control element, putting every layout container into the UIA Control view that screen readers (Narrator, NVDA) walk. This makes the layout peer opt-in for the screen-reader (Control/Content) tree: - AutomationId only: stays discoverable in the raw view for UI tests and reports Custom with an empty localized control type instead of a Pane. - AutomationProperties.IsInAccessibleTree="True": opts the panel into the accessibility tree (Content view) so screen readers stop on it. - SemanticProperties.Description / Hint: treated as an implicit opt-in. - Explicit IsInAccessibleTree="False" (Raw) always wins over any opt-in. Co-authored-by: Vignesh-SF3580 <102575140+Vignesh-SF3580@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…et11) Net11.0 version of #35597 (follow-up to #35562). Targets net11.0 so the new public API can land, and actions the deferred ".NET11.0" TODO by making MauiLayoutAutomationPeer public instead of internal. - MauiLayoutAutomationPeer is now `public` (class + constructor); the "TODO: Make this class public in .NET11.0" is resolved. - Added the corresponding net-windows PublicAPI.Unshipped.txt entries (type, constructor, and the six protected overrides), matching the existing MauiButtonAutomationPeer pattern. - LayoutPanel.OnCreateAutomationPeer + the AutomationId/screen-reader opt-in behavior are unchanged from #35597. Co-authored-by: Redth <jondick@gmail.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Note
Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment whether this change resolves your issue. Thank you!
This pull request adds a custom automation peer to
LayoutPanelon Windows to improve accessibility support for layout containers in .NET MAUI. The newMauiLayoutAutomationPeerprovides more accurate class names, control types, and automation exposure for layouts, and includes comprehensive tests to validate this behavior.Description of Change
Accessibility improvements for layout containers:
MauiLayoutAutomationPeerthat customizes accessibility for layout containers by overriding methods such asGetClassNameCore,GetAutomationControlTypeCore,IsKeyboardFocusableCore,IsControlElementCore, andIsContentElementCore. This ensures screen readers and automation tools receive accurate information about layout elements.OnCreateAutomationPeer()inLayoutPanelto return an instance ofMauiLayoutAutomationPeer, enabling the new accessibility behavior. [1] [2]Test coverage for layout automation:
LayoutTests.Windows.csto verify that the correct automation peer is created, the control type is set toPane, the class name reflects the cross-platform layout type, and that automation tree exposure and keyboard focusability behave as expected. Tests also cover runtime changes toAutomationId.Dependency and using updates:
Issues Fixed
Fixes #4715
Tested the behavior in the following platforms