Skip to content

Commit 8285f8d

Browse files
[SettingsCard] Accesibility improvements (#284)
* Push * Code cleanup * Updating samples * Update SettingsCard.xaml * Minor cleanup * Fix initial render bug * A11y improvements for SettingsCard * Updates to SettingsExpander narrator announcements * Update hover color in highcontrast * Adding click event to Clickable card sample --------- Co-authored-by: Arlo Godfrey <[email protected]>
1 parent eb98b48 commit 8285f8d

File tree

6 files changed

+86
-45
lines changed

6 files changed

+86
-45
lines changed

components/SettingsControls/samples/ClickableSettingsCardSample.xaml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
1+
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
22
<Page x:Class="SettingsControlsExperiment.Samples.ClickableSettingsCardSample"
33
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
44
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
@@ -9,6 +9,7 @@
99
mc:Ignorable="d">
1010
<StackPanel Spacing="4">
1111
<controls:SettingsCard x:Name="settingsCard"
12+
Click="OnCardClicked"
1213
Description="A SettingsCard can be made clickable and you can leverage the Command property or Click event."
1314
Header="A clickable SettingsCard"
1415
HeaderIcon="{ui:FontIcon Glyph=&#xE799;}"
@@ -20,13 +21,15 @@
2021

2122
<controls:SettingsCard ActionIcon="{ui:FontIcon Glyph=&#xE8A7;}"
2223
ActionIconToolTip="Open in new window"
24+
Click="OnCardClicked"
2325
Description="You can customize the ActionIcon and ActionIconToolTip."
2426
Header="Customizing the ActionIcon"
2527
HeaderIcon="{ui:FontIcon Glyph=&#xE774;}"
2628
IsClickEnabled="True"
2729
IsEnabled="{x:Bind IsCardEnabled, Mode=OneWay}" />
2830

29-
<controls:SettingsCard Header="Hiding the ActionIcon"
31+
<controls:SettingsCard Click="OnCardClicked"
32+
Header="Hiding the ActionIcon"
3033
HeaderIcon="{ui:FontIcon Glyph=&#xE72E;}"
3134
IsActionIconVisible="False"
3235
IsClickEnabled="True"

components/SettingsControls/src/SettingsCard/SettingsCard.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,7 @@ protected override void OnApplyTemplate()
7474
OnDescriptionChanged();
7575
OnIsClickEnabledChanged();
7676
CheckInitialVisualState();
77-
78-
RegisterAutomation();
77+
SetAccessibleContentName();
7978
RegisterPropertyChangedCallback(ContentProperty, OnContentChanged);
8079
IsEnabledChanged += OnIsEnabledChanged;
8180
}
@@ -91,11 +90,12 @@ private void CheckInitialVisualState()
9190
contentAlignmentStatesGroup.CurrentStateChanged += this.ContentAlignmentStates_Changed;
9291
}
9392
}
94-
private void RegisterAutomation()
93+
94+
// We automatically set the AutomationProperties.Name of the Content if not configured.
95+
private void SetAccessibleContentName()
9596
{
9697
if (Header is string headerString && headerString != string.Empty)
9798
{
98-
AutomationProperties.SetName(this, headerString);
9999
// We don't want to override an AutomationProperties.Name that is manually set, or if the Content basetype is of type ButtonBase (the ButtonBase.Content will be used then)
100100
if (Content is UIElement element && string.IsNullOrEmpty(AutomationProperties.GetName(element)) && element.GetType().BaseType != typeof(ButtonBase) && element.GetType() != typeof(TextBlock))
101101
{

components/SettingsControls/src/SettingsCard/SettingsCard.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@
8080
<StaticResource x:Key="SettingsCardForegroundPointerOver"
8181
ResourceKey="SystemColorHighlightColorBrush" />
8282
<StaticResource x:Key="SettingsCardForegroundPressed"
83-
ResourceKey="SystemColorHighlightTextColorBrush" />
83+
ResourceKey="SystemColorHighlightColorBrush" />
8484
<StaticResource x:Key="SettingsCardForegroundDisabled"
8585
ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
8686

components/SettingsControls/src/SettingsCard/SettingsCardAutomationPeer.cs

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,46 +2,67 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5-
using System;
6-
using System.Collections.Generic;
7-
using System.Text;
8-
95
namespace CommunityToolkit.WinUI.Controls;
106

7+
/// <summary>
8+
/// AutomationPeer for SettingsCard
9+
/// </summary>
10+
public class SettingsCardAutomationPeer : FrameworkElementAutomationPeer
11+
{
12+
/// <summary>
13+
/// Initializes a new instance of the <see cref="SettingsCard"/> class.
14+
/// </summary>
15+
/// <param name="owner">SettingsCard</param>
16+
public SettingsCardAutomationPeer(SettingsCard owner)
17+
: base(owner)
18+
{
19+
}
20+
1121
/// <summary>
12-
/// AutomationPeer for SettingsCard
22+
/// Gets the control type for the element that is associated with the UI Automation peer.
1323
/// </summary>
14-
public class SettingsCardAutomationPeer : FrameworkElementAutomationPeer
24+
/// <returns>The control type.</returns>
25+
protected override AutomationControlType GetAutomationControlTypeCore()
1526
{
16-
/// <summary>
17-
/// Initializes a new instance of the <see cref="SettingsCard"/> class.
18-
/// </summary>
19-
/// <param name="owner">SettingsCard</param>
20-
public SettingsCardAutomationPeer(SettingsCard owner)
21-
: base(owner)
27+
if (Owner is SettingsCard settingsCard && settingsCard.IsClickEnabled)
2228
{
29+
return AutomationControlType.Button;
2330
}
24-
25-
/// <summary>
26-
/// Gets the control type for the element that is associated with the UI Automation peer.
27-
/// </summary>
28-
/// <returns>The control type.</returns>
29-
protected override AutomationControlType GetAutomationControlTypeCore()
31+
else
3032
{
3133
return AutomationControlType.Group;
3234
}
35+
}
3336

34-
/// <summary>
35-
/// Called by GetClassName that gets a human readable name that, in addition to AutomationControlType,
36-
/// differentiates the control represented by this AutomationPeer.
37-
/// </summary>
38-
/// <returns>The string that contains the name.</returns>
39-
protected override string GetClassNameCore()
37+
/// <summary>
38+
/// Called by GetClassName that gets a human readable name that, in addition to AutomationControlType,
39+
/// differentiates the control represented by this AutomationPeer.
40+
/// </summary>
41+
/// <returns>The string that contains the name.</returns>
42+
protected override string GetClassNameCore()
43+
{
44+
return Owner.GetType().Name;
45+
}
46+
47+
protected override string GetNameCore()
48+
{
49+
// We only want to announce the button card name if it is clickable, else it's just a regular card that does not receive focus
50+
if (Owner is SettingsCard owner && owner.IsClickEnabled)
4051
{
41-
string classNameCore = Owner.GetType().Name;
42-
#if DEBUG_AUTOMATION
43-
System.Diagnostics.Debug.WriteLine("SettingsCardAutomationPeer.GetClassNameCore returns " + classNameCore);
44-
#endif
45-
return classNameCore;
52+
string name = AutomationProperties.GetName(owner);
53+
if (!string.IsNullOrEmpty(name))
54+
{
55+
return name;
56+
}
57+
else
58+
{
59+
if (owner.Header is string headerString && !string.IsNullOrEmpty(headerString))
60+
{
61+
return headerString;
62+
}
63+
}
4664
}
65+
66+
return base.GetNameCore();
4767
}
68+
}

components/SettingsControls/src/SettingsExpander/SettingsExpander.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public SettingsExpander()
2525
protected override void OnApplyTemplate()
2626
{
2727
base.OnApplyTemplate();
28-
RegisterAutomation();
28+
SetAccessibleName();
2929

3030
if (_itemsRepeater != null)
3131
{
@@ -43,11 +43,11 @@ protected override void OnApplyTemplate()
4343
}
4444
}
4545

46-
private void RegisterAutomation()
46+
private void SetAccessibleName()
4747
{
48-
if (Header is string headerString && headerString != string.Empty)
48+
if (string.IsNullOrEmpty(AutomationProperties.GetName(this)))
4949
{
50-
if (!string.IsNullOrEmpty(headerString) && string.IsNullOrEmpty(AutomationProperties.GetName(this)))
50+
if (Header is string headerString && !string.IsNullOrEmpty(headerString))
5151
{
5252
AutomationProperties.SetName(this, headerString);
5353
}

components/SettingsControls/src/SettingsExpander/SettingsExpanderAutomationPeer.cs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,28 @@ protected override AutomationControlType GetAutomationControlTypeCore()
3939
/// <returns>The string that contains the name.</returns>
4040
protected override string GetClassNameCore()
4141
{
42-
string classNameCore = Owner.GetType().Name;
43-
#if DEBUG_AUTOMATION
44-
System.Diagnostics.Debug.WriteLine("SettingsCardAutomationPeer.GetClassNameCore returns " + classNameCore);
45-
#endif
46-
return classNameCore;
42+
return Owner.GetType().Name;
43+
}
44+
45+
protected override string GetNameCore()
46+
{
47+
string name = base.GetNameCore();
48+
49+
if (Owner is SettingsExpander owner)
50+
{
51+
if (!string.IsNullOrEmpty(AutomationProperties.GetName(owner)))
52+
{
53+
name = AutomationProperties.GetName(owner);
54+
}
55+
else
56+
{
57+
if (owner.Header is string headerString && !string.IsNullOrEmpty(headerString))
58+
{
59+
name = headerString;
60+
}
61+
}
62+
}
63+
return name;
4764
}
4865

4966
/// <summary>

0 commit comments

Comments
 (0)