Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added automation peers for BladeView and BladeItem controls #3518

Merged
merged 10 commits into from
Dec 15, 2020
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public partial class BladeItem
/// </summary>
public static readonly DependencyProperty CloseButtonForegroundProperty = DependencyProperty.Register(nameof(CloseButtonForeground), typeof(Brush), typeof(BladeItem), new PropertyMetadata(new SolidColorBrush(Colors.Black)));

private WeakReference<BladeView> _parentBladeView;

/// <summary>
/// Gets or sets the foreground color of the close button
/// </summary>
Expand Down Expand Up @@ -84,6 +86,16 @@ public bool IsOpen
set { SetValue(IsOpenProperty, value); }
}

internal BladeView ParentBladeView
{
get
{
this._parentBladeView.TryGetTarget(out var bladeView);
return bladeView;
}
set => this._parentBladeView = new WeakReference<BladeView>(value);
}

private static void IsOpenChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
BladeItem bladeItem = (BladeItem)dependencyObject;
Expand Down
11 changes: 11 additions & 0 deletions Microsoft.Toolkit.Uwp.UI.Controls/BladeView/BladeItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

using System;
using Microsoft.Toolkit.Uwp.Extensions;
using Microsoft.Toolkit.Uwp.UI.Automation.Peers;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation;
using Windows.UI.Xaml.Automation.Peers;
using Windows.UI.Xaml.Controls;

namespace Microsoft.Toolkit.Uwp.UI.Controls
Expand Down Expand Up @@ -92,6 +94,15 @@ protected override void OnCollapsed(EventArgs args)
}
}

/// <summary>
/// Creates AutomationPeer (<see cref="UIElement.OnCreateAutomationPeer"/>)
/// </summary>
/// <returns>An automation peer for this <see cref="BladeItem"/>.</returns>
protected override AutomationPeer OnCreateAutomationPeer()
{
return new BladeItemAutomationPeer(this);
}

private void OnSizeChanged(object sender, SizeChangedEventArgs sizeChangedEventArgs)
{
if (IsExpanded)
Expand Down
163 changes: 163 additions & 0 deletions Microsoft.Toolkit.Uwp.UI.Controls/BladeView/BladeItemAutomationPeer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
// 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.

using Microsoft.Toolkit.Uwp.UI.Controls;
using Microsoft.Toolkit.Uwp.UI.Extensions;
using Windows.UI.Xaml.Automation;
using Windows.UI.Xaml.Automation.Peers;
using Windows.UI.Xaml.Controls;

namespace Microsoft.Toolkit.Uwp.UI.Automation.Peers
{
/// <summary>
/// Defines a framework element automation peer for the <see cref="BladeItem"/>.
/// </summary>
public class BladeItemAutomationPeer : FrameworkElementAutomationPeer
{
/// <summary>
/// Initializes a new instance of the <see cref="BladeItemAutomationPeer"/> class.
/// </summary>
/// <param name="owner">
/// The <see cref="BladeItem" /> that is associated with this <see cref="T:Windows.UI.Xaml.Automation.Peers.BladeItemAutomationPeer" />.
/// </param>
public BladeItemAutomationPeer(BladeItem owner)
: base(owner)
{
}

private BladeItem OwnerBladeItem
{
get { return this.Owner as BladeItem; }
}

/// <summary>
/// Gets the control type for the element that is associated with the UI Automation peer.
/// </summary>
/// <returns>The control type.</returns>
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.ListItem;
}

/// <summary>
/// Called by GetClassName that gets a human readable name that, in addition to AutomationControlType,
/// differentiates the control represented by this AutomationPeer.
/// </summary>
/// <returns>The string that contains the name.</returns>
protected override string GetClassNameCore()
{
return Owner.GetType().Name;
}

/// <summary>
/// Called by GetName.
/// </summary>
/// <returns>
/// Returns the first of these that is not null or empty:
/// - Value returned by the base implementation
/// - Name of the owning BladeItem
/// - BladeItem class name
/// </returns>
protected override string GetNameCore()
{
string name = AutomationProperties.GetName(this.OwnerBladeItem);
if (!string.IsNullOrEmpty(name))
{
return name;
}

name = this.OwnerBladeItem.Name;
if (!string.IsNullOrEmpty(name))
{
return name;
}

name = this.OwnerBladeItem.Header?.ToString();
if (!string.IsNullOrEmpty(name))
{
return name;
}

TextBlock textBlock = this.OwnerBladeItem.FindDescendant<TextBlock>();
Copy link
Member

@michael-hawker michael-hawker Dec 3, 2020

Choose a reason for hiding this comment

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

@jamesmcroft the BladeItem.Header should be the 'Title' of the Blade, do we want to try and explicitly convert that to a string as a first step?

Copy link
Member Author

Choose a reason for hiding this comment

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

Sorted! Apologies for the delay on sorting this out.

if (textBlock != null)
{
return textBlock.Text;
}

name = base.GetNameCore();
if (!string.IsNullOrEmpty(name))
{
return name;
}

return string.Empty;
}

/// <summary>
/// Called by GetAutomationId that gets the **AutomationId** of the element that is associated with the automation peer.
/// </summary>
/// <returns>
/// The string that contains the automation ID.
/// </returns>
protected override string GetAutomationIdCore()
{
string automationId = base.GetAutomationIdCore();
if (!string.IsNullOrEmpty(automationId))
{
return automationId;
}

if (this.OwnerBladeItem != null)
{
return this.GetNameCore();
}

return string.Empty;
}

/// <summary>
/// Returns the size of the set where the element that is associated with the automation peer is located.
/// </summary>
/// <returns>
/// The size of the set.
/// </returns>
protected override int GetSizeOfSetCore()
{
int sizeOfSet = base.GetSizeOfSetCore();

if (sizeOfSet != -1)
{
return sizeOfSet;
}

BladeItem owner = this.OwnerBladeItem;
BladeView parent = owner.ParentBladeView;
sizeOfSet = parent.Items.Count;

return sizeOfSet;
}

/// <summary>
/// Returns the ordinal position in the set for the element that is associated with the automation peer.
/// </summary>
/// <returns>
/// The ordinal position in the set.
/// </returns>
protected override int GetPositionInSetCore()
{
int positionInSet = base.GetPositionInSetCore();

if (positionInSet != -1)
{
return positionInSet;
}

BladeItem owner = this.OwnerBladeItem;
BladeView parent = owner.ParentBladeView;
positionInSet = parent.IndexFromContainer(owner);

return positionInSet;
}
}
}
12 changes: 12 additions & 0 deletions Microsoft.Toolkit.Uwp.UI.Controls/BladeView/BladeView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Microsoft.Toolkit.Uwp.UI.Automation.Peers;
using Microsoft.Toolkit.Uwp.UI.Extensions;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation.Peers;
using Windows.UI.Xaml.Controls;

namespace Microsoft.Toolkit.Uwp.UI.Controls
Expand Down Expand Up @@ -65,6 +67,7 @@ protected override void PrepareContainerForItemOverride(DependencyObject element
if (blade != null)
{
blade.VisibilityChanged += BladeOnVisibilityChanged;
blade.ParentBladeView = this;
}

base.PrepareContainerForItemOverride(element, item);
Expand All @@ -83,6 +86,15 @@ protected override void ClearContainerForItemOverride(DependencyObject element,
base.ClearContainerForItemOverride(element, item);
}

/// <summary>
/// Creates AutomationPeer (<see cref="UIElement.OnCreateAutomationPeer"/>)
/// </summary>
/// <returns>An automation peer for this <see cref="BladeView"/>.</returns>
protected override AutomationPeer OnCreateAutomationPeer()
{
return new BladeViewAutomationPeer(this);
}

private void CycleBlades()
{
ActiveBlades = new ObservableCollection<BladeItem>();
Expand Down
115 changes: 115 additions & 0 deletions Microsoft.Toolkit.Uwp.UI.Controls/BladeView/BladeViewAutomationPeer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// 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.

using System.Collections.Generic;
using Microsoft.Toolkit.Uwp.UI.Controls;
using Windows.UI.Xaml.Automation;
using Windows.UI.Xaml.Automation.Peers;
using Windows.UI.Xaml.Controls;

namespace Microsoft.Toolkit.Uwp.UI.Automation.Peers
{
/// <summary>
/// Defines a framework element automation peer for the <see cref="BladeView"/> control.
/// </summary>
public class BladeViewAutomationPeer : ItemsControlAutomationPeer
{
/// <summary>
/// Initializes a new instance of the <see cref="BladeViewAutomationPeer"/> class.
/// </summary>
/// <param name="owner">
/// The <see cref="BladeView" /> that is associated with this <see cref="T:Windows.UI.Xaml.Automation.Peers.BladeViewAutomationPeer" />.
/// </param>
public BladeViewAutomationPeer(BladeView owner)
: base(owner)
{
}

private BladeView OwningBladeView
{
get
{
return Owner as BladeView;
}
}

/// <summary>
/// Gets the control type for the element that is associated with the UI Automation peer.
/// </summary>
/// <returns>The control type.</returns>
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.List;
}

/// <summary>
/// Called by GetClassName that gets a human readable name that, in addition to AutomationControlType,
/// differentiates the control represented by this AutomationPeer.
/// </summary>
/// <returns>The string that contains the name.</returns>
protected override string GetClassNameCore()
{
return Owner.GetType().Name;
}

/// <summary>
/// Called by GetName.
/// </summary>
/// <returns>
/// Returns the first of these that is not null or empty:
/// - Value returned by the base implementation
/// - Name of the owning BladeView
/// - BladeView class name
/// </returns>
protected override string GetNameCore()
{
string name = AutomationProperties.GetName(this.OwningBladeView);
if (!string.IsNullOrEmpty(name))
{
return name;
}

name = this.OwningBladeView.Name;
if (!string.IsNullOrEmpty(name))
{
return name;
}

name = base.GetNameCore();
if (!string.IsNullOrEmpty(name))
{
return name;
}

return string.Empty;
}

/// <summary>
/// Gets the collection of elements that are represented in the UI Automation tree as immediate
/// child elements of the automation peer.
/// </summary>
/// <returns>The children elements.</returns>
protected override IList<AutomationPeer> GetChildrenCore()
{
BladeView owner = OwningBladeView;

ItemCollection items = owner.Items;
if (items.Count <= 0)
{
return null;
}

List<AutomationPeer> peers = new List<AutomationPeer>(items.Count);
for (int i = 0; i < items.Count; i++)
{
if (owner.ContainerFromIndex(i) is BladeItem element)
{
peers.Add(FromElement(element) ?? CreatePeerForElement(element));
}
}

return peers;
}
}
}
Loading