Skip to content

Commit 8ccfaff

Browse files
Merge pull request #3518 from windows-toolkit/jamesmcroft/3517-bladeview-automation
Added automation peers for BladeView and BladeItem controls
2 parents c402640 + 32e3c4b commit 8ccfaff

File tree

7 files changed

+350
-0
lines changed

7 files changed

+350
-0
lines changed

Microsoft.Toolkit.Uwp.UI.Controls/BladeView/BladeItem.Properties.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ public partial class BladeItem
3939
/// </summary>
4040
public static readonly DependencyProperty CloseButtonForegroundProperty = DependencyProperty.Register(nameof(CloseButtonForeground), typeof(Brush), typeof(BladeItem), new PropertyMetadata(new SolidColorBrush(Colors.Black)));
4141

42+
private WeakReference<BladeView> _parentBladeView;
43+
4244
/// <summary>
4345
/// Gets or sets the foreground color of the close button
4446
/// </summary>
@@ -84,6 +86,16 @@ public bool IsOpen
8486
set { SetValue(IsOpenProperty, value); }
8587
}
8688

89+
internal BladeView ParentBladeView
90+
{
91+
get
92+
{
93+
this._parentBladeView.TryGetTarget(out var bladeView);
94+
return bladeView;
95+
}
96+
set => this._parentBladeView = new WeakReference<BladeView>(value);
97+
}
98+
8799
private static void IsOpenChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
88100
{
89101
BladeItem bladeItem = (BladeItem)dependencyObject;

Microsoft.Toolkit.Uwp.UI.Controls/BladeView/BladeItem.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44

55
using System;
66
using Microsoft.Toolkit.Uwp.Extensions;
7+
using Microsoft.Toolkit.Uwp.UI.Automation.Peers;
78
using Windows.UI.Xaml;
89
using Windows.UI.Xaml.Automation;
10+
using Windows.UI.Xaml.Automation.Peers;
911
using Windows.UI.Xaml.Controls;
1012

1113
namespace Microsoft.Toolkit.Uwp.UI.Controls
@@ -92,6 +94,15 @@ protected override void OnCollapsed(EventArgs args)
9294
}
9395
}
9496

97+
/// <summary>
98+
/// Creates AutomationPeer (<see cref="UIElement.OnCreateAutomationPeer"/>)
99+
/// </summary>
100+
/// <returns>An automation peer for this <see cref="BladeItem"/>.</returns>
101+
protected override AutomationPeer OnCreateAutomationPeer()
102+
{
103+
return new BladeItemAutomationPeer(this);
104+
}
105+
95106
private void OnSizeChanged(object sender, SizeChangedEventArgs sizeChangedEventArgs)
96107
{
97108
if (IsExpanded)
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
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 Microsoft.Toolkit.Uwp.UI.Extensions;
7+
using Windows.UI.Xaml.Automation;
8+
using Windows.UI.Xaml.Automation.Peers;
9+
using Windows.UI.Xaml.Controls;
10+
11+
namespace Microsoft.Toolkit.Uwp.UI.Automation.Peers
12+
{
13+
/// <summary>
14+
/// Defines a framework element automation peer for the <see cref="BladeItem"/>.
15+
/// </summary>
16+
public class BladeItemAutomationPeer : FrameworkElementAutomationPeer
17+
{
18+
/// <summary>
19+
/// Initializes a new instance of the <see cref="BladeItemAutomationPeer"/> class.
20+
/// </summary>
21+
/// <param name="owner">
22+
/// The <see cref="BladeItem" /> that is associated with this <see cref="T:Windows.UI.Xaml.Automation.Peers.BladeItemAutomationPeer" />.
23+
/// </param>
24+
public BladeItemAutomationPeer(BladeItem owner)
25+
: base(owner)
26+
{
27+
}
28+
29+
private BladeItem OwnerBladeItem
30+
{
31+
get { return this.Owner as BladeItem; }
32+
}
33+
34+
/// <summary>
35+
/// Gets the control type for the element that is associated with the UI Automation peer.
36+
/// </summary>
37+
/// <returns>The control type.</returns>
38+
protected override AutomationControlType GetAutomationControlTypeCore()
39+
{
40+
return AutomationControlType.ListItem;
41+
}
42+
43+
/// <summary>
44+
/// Called by GetClassName that gets a human readable name that, in addition to AutomationControlType,
45+
/// differentiates the control represented by this AutomationPeer.
46+
/// </summary>
47+
/// <returns>The string that contains the name.</returns>
48+
protected override string GetClassNameCore()
49+
{
50+
return Owner.GetType().Name;
51+
}
52+
53+
/// <summary>
54+
/// Called by GetName.
55+
/// </summary>
56+
/// <returns>
57+
/// Returns the first of these that is not null or empty:
58+
/// - Value returned by the base implementation
59+
/// - Name of the owning BladeItem
60+
/// - BladeItem class name
61+
/// </returns>
62+
protected override string GetNameCore()
63+
{
64+
string name = AutomationProperties.GetName(this.OwnerBladeItem);
65+
if (!string.IsNullOrEmpty(name))
66+
{
67+
return name;
68+
}
69+
70+
name = this.OwnerBladeItem.Name;
71+
if (!string.IsNullOrEmpty(name))
72+
{
73+
return name;
74+
}
75+
76+
name = this.OwnerBladeItem.Header?.ToString();
77+
if (!string.IsNullOrEmpty(name))
78+
{
79+
return name;
80+
}
81+
82+
TextBlock textBlock = this.OwnerBladeItem.FindDescendant<TextBlock>();
83+
if (textBlock != null)
84+
{
85+
return textBlock.Text;
86+
}
87+
88+
name = base.GetNameCore();
89+
if (!string.IsNullOrEmpty(name))
90+
{
91+
return name;
92+
}
93+
94+
return string.Empty;
95+
}
96+
97+
/// <summary>
98+
/// Called by GetAutomationId that gets the **AutomationId** of the element that is associated with the automation peer.
99+
/// </summary>
100+
/// <returns>
101+
/// The string that contains the automation ID.
102+
/// </returns>
103+
protected override string GetAutomationIdCore()
104+
{
105+
string automationId = base.GetAutomationIdCore();
106+
if (!string.IsNullOrEmpty(automationId))
107+
{
108+
return automationId;
109+
}
110+
111+
if (this.OwnerBladeItem != null)
112+
{
113+
return this.GetNameCore();
114+
}
115+
116+
return string.Empty;
117+
}
118+
119+
/// <summary>
120+
/// Returns the size of the set where the element that is associated with the automation peer is located.
121+
/// </summary>
122+
/// <returns>
123+
/// The size of the set.
124+
/// </returns>
125+
protected override int GetSizeOfSetCore()
126+
{
127+
int sizeOfSet = base.GetSizeOfSetCore();
128+
129+
if (sizeOfSet != -1)
130+
{
131+
return sizeOfSet;
132+
}
133+
134+
BladeItem owner = this.OwnerBladeItem;
135+
BladeView parent = owner.ParentBladeView;
136+
sizeOfSet = parent.Items.Count;
137+
138+
return sizeOfSet;
139+
}
140+
141+
/// <summary>
142+
/// Returns the ordinal position in the set for the element that is associated with the automation peer.
143+
/// </summary>
144+
/// <returns>
145+
/// The ordinal position in the set.
146+
/// </returns>
147+
protected override int GetPositionInSetCore()
148+
{
149+
int positionInSet = base.GetPositionInSetCore();
150+
151+
if (positionInSet != -1)
152+
{
153+
return positionInSet;
154+
}
155+
156+
BladeItem owner = this.OwnerBladeItem;
157+
BladeView parent = owner.ParentBladeView;
158+
positionInSet = parent.IndexFromContainer(owner);
159+
160+
return positionInSet;
161+
}
162+
}
163+
}

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@
66
using System.Collections.Generic;
77
using System.Collections.ObjectModel;
88
using System.Linq;
9+
using Microsoft.Toolkit.Uwp.UI.Automation.Peers;
910
using Microsoft.Toolkit.Uwp.UI.Extensions;
1011
using Windows.Foundation;
1112
using Windows.Foundation.Collections;
1213
using Windows.UI.Core;
1314
using Windows.UI.Xaml;
15+
using Windows.UI.Xaml.Automation.Peers;
1416
using Windows.UI.Xaml.Controls;
1517

1618
namespace Microsoft.Toolkit.Uwp.UI.Controls
@@ -65,6 +67,7 @@ protected override void PrepareContainerForItemOverride(DependencyObject element
6567
if (blade != null)
6668
{
6769
blade.VisibilityChanged += BladeOnVisibilityChanged;
70+
blade.ParentBladeView = this;
6871
}
6972

7073
base.PrepareContainerForItemOverride(element, item);
@@ -83,6 +86,15 @@ protected override void ClearContainerForItemOverride(DependencyObject element,
8386
base.ClearContainerForItemOverride(element, item);
8487
}
8588

89+
/// <summary>
90+
/// Creates AutomationPeer (<see cref="UIElement.OnCreateAutomationPeer"/>)
91+
/// </summary>
92+
/// <returns>An automation peer for this <see cref="BladeView"/>.</returns>
93+
protected override AutomationPeer OnCreateAutomationPeer()
94+
{
95+
return new BladeViewAutomationPeer(this);
96+
}
97+
8698
private void CycleBlades()
8799
{
88100
ActiveBlades = new ObservableCollection<BladeItem>();
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
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 System.Collections.Generic;
6+
using Microsoft.Toolkit.Uwp.UI.Controls;
7+
using Windows.UI.Xaml.Automation;
8+
using Windows.UI.Xaml.Automation.Peers;
9+
using Windows.UI.Xaml.Controls;
10+
11+
namespace Microsoft.Toolkit.Uwp.UI.Automation.Peers
12+
{
13+
/// <summary>
14+
/// Defines a framework element automation peer for the <see cref="BladeView"/> control.
15+
/// </summary>
16+
public class BladeViewAutomationPeer : ItemsControlAutomationPeer
17+
{
18+
/// <summary>
19+
/// Initializes a new instance of the <see cref="BladeViewAutomationPeer"/> class.
20+
/// </summary>
21+
/// <param name="owner">
22+
/// The <see cref="BladeView" /> that is associated with this <see cref="T:Windows.UI.Xaml.Automation.Peers.BladeViewAutomationPeer" />.
23+
/// </param>
24+
public BladeViewAutomationPeer(BladeView owner)
25+
: base(owner)
26+
{
27+
}
28+
29+
private BladeView OwningBladeView
30+
{
31+
get
32+
{
33+
return Owner as BladeView;
34+
}
35+
}
36+
37+
/// <summary>
38+
/// Gets the control type for the element that is associated with the UI Automation peer.
39+
/// </summary>
40+
/// <returns>The control type.</returns>
41+
protected override AutomationControlType GetAutomationControlTypeCore()
42+
{
43+
return AutomationControlType.List;
44+
}
45+
46+
/// <summary>
47+
/// Called by GetClassName that gets a human readable name that, in addition to AutomationControlType,
48+
/// differentiates the control represented by this AutomationPeer.
49+
/// </summary>
50+
/// <returns>The string that contains the name.</returns>
51+
protected override string GetClassNameCore()
52+
{
53+
return Owner.GetType().Name;
54+
}
55+
56+
/// <summary>
57+
/// Called by GetName.
58+
/// </summary>
59+
/// <returns>
60+
/// Returns the first of these that is not null or empty:
61+
/// - Value returned by the base implementation
62+
/// - Name of the owning BladeView
63+
/// - BladeView class name
64+
/// </returns>
65+
protected override string GetNameCore()
66+
{
67+
string name = AutomationProperties.GetName(this.OwningBladeView);
68+
if (!string.IsNullOrEmpty(name))
69+
{
70+
return name;
71+
}
72+
73+
name = this.OwningBladeView.Name;
74+
if (!string.IsNullOrEmpty(name))
75+
{
76+
return name;
77+
}
78+
79+
name = base.GetNameCore();
80+
if (!string.IsNullOrEmpty(name))
81+
{
82+
return name;
83+
}
84+
85+
return string.Empty;
86+
}
87+
88+
/// <summary>
89+
/// Gets the collection of elements that are represented in the UI Automation tree as immediate
90+
/// child elements of the automation peer.
91+
/// </summary>
92+
/// <returns>The children elements.</returns>
93+
protected override IList<AutomationPeer> GetChildrenCore()
94+
{
95+
BladeView owner = OwningBladeView;
96+
97+
ItemCollection items = owner.Items;
98+
if (items.Count <= 0)
99+
{
100+
return null;
101+
}
102+
103+
List<AutomationPeer> peers = new List<AutomationPeer>(items.Count);
104+
for (int i = 0; i < items.Count; i++)
105+
{
106+
if (owner.ContainerFromIndex(i) is BladeItem element)
107+
{
108+
peers.Add(FromElement(element) ?? CreatePeerForElement(element));
109+
}
110+
}
111+
112+
return peers;
113+
}
114+
}
115+
}

0 commit comments

Comments
 (0)