Skip to content

Conversation

@Tamilarasan-Paranthaman
Copy link
Contributor

@Tamilarasan-Paranthaman Tamilarasan-Paranthaman commented Feb 11, 2025

Description of Change

  • Implemented AutomationPeer support for the Windows Border control.

  • Added keyboard accessibility by invoking the TapGestureRecognizer when the Enter or Space key is pressed, if a TapGestureRecognizer is attached to the Border.

  • The Border can now receive focus (IsTabStop = true) only when a TapGestureRecognizer is added, ensuring it behaves like an interactive element.

  • Accessibility support is implemented using a custom MauiBorderAutomationPeer, derived from FrameworkElementAutomationPeer.

  • This peer is introduced to support accessibility for the custom MauiBorder implementation, which is built using a Panel. Since Panel does not provide a default AutomationPeer, we explicitly define one (MauiBorderAutomationPeer).

Screenshots

Note: In the following video:

  • The first Border (containing the CheckBox) does not have a TapGestureRecognizer, so it does not receive focus during keyboard navigation.

  • The second Border (containing the Label) initially has a TapGestureRecognizer attached. It receives focus as expected, and the Tapped event is correctly fired when pressing the Space or Enter key.

  • The TapGestureRecognizer is then removed at runtime using the “Remove TapGestureRecognizer” button and added again using the “Add TapGestureRecognizer” button.

  • After removing it at runtime, the second Border no longer receives focus. Once it is added back, the focus behavior and keyboard interaction work as expected again.

Screen.Recording.mp4

Overridden Core Methods and their Purpose

1. GetAutomationControlTypeCore()

  • Returns AutomationControlType.Pane, the most appropriate control type for a layout container that doesn't represent a user-interactive control like a button or checkbox.
  • This helps screen readers and other assistive technologies interpret the element as a structural container, which is typical for layout surfaces like borders and panels.

2. GetClassNameCore()

  • Returns Panel to reflect the underlying native element.
  • This helps UI automation tools identify the element’s role, consistent with common patterns in FrameworkElementAutomationPeer.

3. IsControlElementCore()

  • Returns true to ensure the element is included in the Control View, which represents elements relevant to end users.
  • This is important for layout elements that serve grouping or logical structuring purposes rather than being purely decorative.

4. IsContentElementCore()

  • Returns true so the element appears in the Content View, allowing screen readers to expose both this element and its children if they contain user-relevant content.

Issues Fixed

Fixes #27627

@dotnet-policy-service dotnet-policy-service bot added the community ✨ Community Contribution label Feb 11, 2025
@Tamilarasan-Paranthaman Tamilarasan-Paranthaman added the partner/syncfusion Issues / PR's with Syncfusion collaboration label Feb 11, 2025
@jsuarezruiz
Copy link
Contributor

/azp run

@jsuarezruiz jsuarezruiz added platform/windows t/a11y Relates to accessibility labels Feb 12, 2025
@azure-pipelines
Copy link

Azure Pipelines successfully started running 3 pipeline(s).

@tj-devel709 tj-devel709 self-requested a review February 12, 2025 22:19
@PureWeen PureWeen added the do-not-merge Don't merge this PR label Feb 12, 2025
@Tamilarasan-Paranthaman Tamilarasan-Paranthaman marked this pull request as ready for review February 13, 2025 10:19
@Copilot Copilot AI review requested due to automatic review settings February 13, 2025 10:19
@Tamilarasan-Paranthaman Tamilarasan-Paranthaman requested a review from a team as a code owner February 13, 2025 10:19
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot reviewed 4 out of 5 changed files in this pull request and generated no comments.

Files not reviewed (1)
  • src/Core/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt: Language not supported
Comments suppressed due to low confidence (2)

src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue27627.cs:7

  • [nitpick] The class name Issue27627 is not descriptive. Consider renaming it to BorderAutomationPeerTests.
public class Issue27627 : _IssuesUITest

src/Controls/tests/TestCases.HostApp/Issues/Issue27627.cs:19

  • The test case does not verify the functionality of the MauiBorderAutomationPeer. It only waits for the element with the AutomationId 'TestBorder'. Add a more comprehensive test to verify the functionality of the automation peer.
App.WaitForElement("TestBorder");

@jsuarezruiz
Copy link
Contributor

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 3 pipeline(s).

Copy link
Member

@mattleibow mattleibow left a comment

Choose a reason for hiding this comment

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

Just the typical "we can;t do cool new things in .NET 9".

But, I am super out pf the a11y loop here, so can you just update the PR description with info on what your reasonoing is with the 4 methods in the peer? The Get*Core methods. I see the other 2 peers we have in maui do not have these.

Also, just for confirmation, can you still select elements inside the border via the various a11y nav options - like keyboard and such?


namespace Microsoft.Maui.Platform
{
public class MauiBorderAutomationPeer : FrameworkElementAutomationPeer
Copy link
Member

Choose a reason for hiding this comment

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

This should be internal for .NET 9, and public in .NET 10.

Can you make this internal for now, and then open an issue so we can make it public for .NET 10.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As you suggested, I changed it to internal, created a new issue #30205 to track this change, and included it for reference.

[Category(UITestCategories.Border)]
public void VerifyBorderAutomationPeer()
{
App.WaitForElement("TestBorder");
Copy link
Member

Choose a reason for hiding this comment

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

Before you set the automation peer, is this not possible? I mean, this test appears to be looking for a element with this ID, so I just want to check if the test would fail without this new peer.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, the test failed without the new peer, and it passed after adding it. I have attached the output images for your reference.

Without this peer With this peer

@Tamilarasan-Paranthaman
Copy link
Contributor Author

Just the typical "we can;t do cool new things in .NET 9".

But, I am super out pf the a11y loop here, so can you just update the PR description with info on what your reasonoing is with the 4 methods in the peer? The Get*Core methods. I see the other 2 peers we have in maui do not have these.

Also, just for confirmation, can you still select elements inside the border via the various a11y nav options - like keyboard and such?

@mattleibow, I have updated the PR description with the relevant details. Regarding accessibility navigation, yes, it still allows navigating to the child elements within the Border. For example, if an Entry is placed inside the Border, pressing the Tab key will move focus to the Entry as expected.

Copy link
Member

@PureWeen PureWeen left a comment

Choose a reason for hiding this comment

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

The automation peer needs to only activate when a gesture is attached to it.

Similar to how android and ios work where we change the accessibility features.

@PureWeen PureWeen added this to the .NET 10 SR1 milestone Oct 18, 2025
@PureWeen PureWeen added the p/0 Work that we can't release without label Oct 18, 2025
@jsuarezruiz
Copy link
Contributor

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 3 pipeline(s).


protected override bool IsKeyboardFocusableCore() => true;

protected override bool IsControlElementCore() => true;
Copy link
Contributor

@jsuarezruiz jsuarezruiz Oct 23, 2025

Choose a reason for hiding this comment

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

Maybe a comment would be nice here:

  • Control View: Contains user-interactive borders (with gesture recognizers)
  • Content View: Allows screen readers to announce border structure

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have added the comments

{
var grid = new Grid();

var border = new Border
Copy link
Contributor

Choose a reason for hiding this comment

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

Could expand the sample to test more scenarios?

  • Nested Borders. Each gets own automation peer via OnCreateAutomationPeer()
  • Border with custom Content. IsContentElementCore = true ensures nested content exposed to screen readers

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jsuarezruiz, I have modified the test sample as suggested.

@github-project-automation github-project-automation bot moved this from Todo to Changes Requested in MAUI SDK Ongoing Oct 23, 2025
@Tamilarasan-Paranthaman
Copy link
Contributor Author

The automation peer needs to only activate when a gesture is attached to it.

Similar to how android and ios work where we change the accessibility features.

@PureWeen, I have modified the implementation as suggested and updated the details in the PR description.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-controls-border Border community ✨ Community Contribution do-not-merge Don't merge this PR p/0 Work that we can't release without partner/syncfusion Issues / PR's with Syncfusion collaboration platform/windows t/a11y Relates to accessibility

Projects

Status: Changes Requested

Development

Successfully merging this pull request may close these issues.

Adding AutomationPeers to Windows Borders

4 participants