Skip to content

Commit fd511a4

Browse files
author
msftbot[bot]
authored
Added automation peer class for expander (#3504)
## Fixes #3502 <!-- Add the relevant issue number after the "#" mentioned above (for ex: Fixes #1234) which will automatically close the issue once the PR is merged. --> Changes have been made to introduce an `AutomationPeer` for the `Expander` control to improve the ability for UI testing this control. ## PR Type What kind of change does this PR introduce? <!-- Please uncomment one or more that apply to this PR. --> - Bugfix <!-- - Feature --> <!-- - Code style update (formatting) --> <!-- - Refactoring (no functional changes, no api changes) --> <!-- - Build or CI related changes --> <!-- - Documentation content changes --> <!-- - Sample app changes --> <!-- - Other... Please describe: --> ## What is the current behavior? <!-- Please describe the current behavior that you are modifying, or link to a relevant issue. --> Currently, when trying to access an `Expander` control by an Automation ID or other automation property, it is not possible as this is not propagated correctly. ## What is the new behavior? <!-- Describe how was this issue resolved or changed? --> A `ExpanderAutomationPeer` has been added which is used by the `Expander` control in order to surface automation properties correctly. The automation peer not only surfaces up the Automation ID but has been coded so that the toggle state of the control is also available. Below is the before and after of the UI Automation tree. **Before** <img width="381" alt="Before" src="https://user-images.githubusercontent.com/13505183/94348158-d57bf400-0031-11eb-9699-6414ab0e2379.png"> **After** <img width="368" alt="After" src="https://user-images.githubusercontent.com/13505183/94348160-da40a800-0031-11eb-9ede-2f15860ca141.png"> As you can tell from the change, the ability to traverse the UI Automation tree is vastly improved allowing the `Expander`'s content to be surfaced correctly instead of separate UI elements. ## PR Checklist Please check if your PR fulfills the following requirements: - [x] Tested code with current [supported SDKs](../readme.md#supported) - [ ] Pull Request has been submitted to the documentation repository [instructions](..\contributing.md#docs). Link: <!-- docs PR link --> - [x] Sample in sample app has been added / updated (for bug fixes / features) - [ ] Icon has been created (if new sample) following the [Thumbnail Style Guide and templates](https://github.com/windows-toolkit/WindowsCommunityToolkit-design-assets) - [ ] Tests for the changes have been added (for bug fixes / features) (if applicable) - [x] Header has been added to all new source files (run *build/UpdateHeaders.bat*) - [x] Contains **NO** breaking changes <!-- If this PR contains a breaking change, please describe the impact and migration path for existing applications below. Please note that breaking changes are likely to be rejected. -->
2 parents 27c66f4 + b74914a commit fd511a4

File tree

2 files changed

+127
-0
lines changed

2 files changed

+127
-0
lines changed

Microsoft.Toolkit.Uwp.UI.Controls/Expander/Expander.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System;
6+
using Microsoft.Toolkit.Uwp.UI.Automation.Peers;
67
using Windows.System;
78
using Windows.UI.Xaml;
9+
using Windows.UI.Xaml.Automation.Peers;
810
using Windows.UI.Xaml.Controls;
911
using Windows.UI.Xaml.Controls.Primitives;
1012
using Windows.UI.Xaml.Input;
@@ -76,6 +78,15 @@ protected virtual void OnCollapsed(EventArgs args)
7678
Collapsed?.Invoke(this, args);
7779
}
7880

81+
/// <summary>
82+
/// Creates AutomationPeer (<see cref="UIElement.OnCreateAutomationPeer"/>)
83+
/// </summary>
84+
/// <returns>An automation peer for this <see cref="Expander"/>.</returns>
85+
protected override AutomationPeer OnCreateAutomationPeer()
86+
{
87+
return new ExpanderAutomationPeer(this);
88+
}
89+
7990
private void ExpanderToggleButtonPart_KeyDown(object sender, KeyRoutedEventArgs e)
8091
{
8192
if (e.Key != VirtualKey.Enter)
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using Microsoft.Toolkit.Uwp.UI.Controls;
6+
using Windows.UI.Xaml.Automation;
7+
using Windows.UI.Xaml.Automation.Peers;
8+
using Windows.UI.Xaml.Automation.Provider;
9+
10+
namespace Microsoft.Toolkit.Uwp.UI.Automation.Peers
11+
{
12+
/// <summary>
13+
/// Defines a framework element automation peer for the <see cref="Expander"/> control.
14+
/// </summary>
15+
public class ExpanderAutomationPeer : FrameworkElementAutomationPeer, IToggleProvider
16+
{
17+
/// <summary>
18+
/// Initializes a new instance of the <see cref="ExpanderAutomationPeer"/> class.
19+
/// </summary>
20+
/// <param name="owner">
21+
/// The <see cref="Expander" /> that is associated with this <see cref="T:Windows.UI.Xaml.Automation.Peers.ExpanderAutomationPeer" />.
22+
/// </param>
23+
public ExpanderAutomationPeer(Expander owner)
24+
: base(owner)
25+
{
26+
}
27+
28+
/// <summary>Gets the toggle state of the control.</summary>
29+
/// <returns>The toggle state of the control, as a value of the enumeration.</returns>
30+
public ToggleState ToggleState => OwningExpander.IsExpanded ? ToggleState.On : ToggleState.Off;
31+
32+
private Expander OwningExpander
33+
{
34+
get
35+
{
36+
return Owner as Expander;
37+
}
38+
}
39+
40+
/// <summary>Cycles through the toggle states of a control.</summary>
41+
public void Toggle()
42+
{
43+
if (!IsEnabled())
44+
{
45+
throw new ElementNotEnabledException();
46+
}
47+
48+
OwningExpander.IsExpanded = !OwningExpander.IsExpanded;
49+
}
50+
51+
/// <summary>
52+
/// Gets the control type for the element that is associated with the UI Automation peer.
53+
/// </summary>
54+
/// <returns>The control type.</returns>
55+
protected override AutomationControlType GetAutomationControlTypeCore()
56+
{
57+
return AutomationControlType.Custom;
58+
}
59+
60+
/// <summary>
61+
/// Called by GetClassName that gets a human readable name that, in addition to AutomationControlType,
62+
/// differentiates the control represented by this AutomationPeer.
63+
/// </summary>
64+
/// <returns>The string that contains the name.</returns>
65+
protected override string GetClassNameCore()
66+
{
67+
return Owner.GetType().Name;
68+
}
69+
70+
/// <summary>
71+
/// Called by GetName.
72+
/// </summary>
73+
/// <returns>
74+
/// Returns the first of these that is not null or empty:
75+
/// - Value returned by the base implementation
76+
/// - Name of the owning Expander
77+
/// - Expander class name
78+
/// </returns>
79+
protected override string GetNameCore()
80+
{
81+
string name = base.GetNameCore();
82+
if (!string.IsNullOrEmpty(name))
83+
{
84+
return name;
85+
}
86+
87+
if (this.OwningExpander != null)
88+
{
89+
name = this.OwningExpander.Name;
90+
}
91+
92+
if (string.IsNullOrEmpty(name))
93+
{
94+
name = this.GetClassName();
95+
}
96+
97+
return name;
98+
}
99+
100+
/// <summary>
101+
/// Gets the control pattern that is associated with the specified Windows.UI.Xaml.Automation.Peers.PatternInterface.
102+
/// </summary>
103+
/// <param name="patternInterface">A value from the Windows.UI.Xaml.Automation.Peers.PatternInterface enumeration.</param>
104+
/// <returns>The object that supports the specified pattern, or null if unsupported.</returns>
105+
protected override object GetPatternCore(PatternInterface patternInterface)
106+
{
107+
switch (patternInterface)
108+
{
109+
case PatternInterface.Toggle:
110+
return this;
111+
}
112+
113+
return base.GetPatternCore(patternInterface);
114+
}
115+
}
116+
}

0 commit comments

Comments
 (0)