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 @@ -84,6 +84,8 @@ public bool IsOpen
set { SetValue(IsOpenProperty, value); }
}

internal BladeView ParentBladeView { get; set; }

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
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// 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.Linq;
using Microsoft.Toolkit.Uwp.UI.Controls;
using Windows.UI.Xaml.Automation.Peers;

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.Custom;
}

/// <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()
{
int? index = this.OwnerBladeItem.ParentBladeView.GetBladeItems().ToList().IndexOf(this.OwnerBladeItem);
Copy link
Contributor

Choose a reason for hiding this comment

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

You should probably add 1 to the index so the blades will be named "blade 1", "blade 2",.. instead of "blade 0", "blade 1",... This will be more "natural" for the users.


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

if (this.OwnerBladeItem != null && !string.IsNullOrEmpty(this.OwnerBladeItem.Name))
{
return this.OwnerBladeItem.Name;
michael-hawker marked this conversation as resolved.
Show resolved Hide resolved
}

if (string.IsNullOrEmpty(name))
{
name = this.GetClassName();
}

return $"{name} {index}";
}
}
}
20 changes: 20 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 Expand Up @@ -200,5 +212,13 @@ private void ItemsVectorChanged(IObservableVector<object> sender, IVectorChanged
GetScrollViewer()?.ChangeView(_scrollViewer.ScrollableWidth, null, null);
}
}

internal IEnumerable<BladeItem> GetBladeItems()
{
return Enumerable
.Range(0, Items.Count)
.Select(idx => (BladeItem)ContainerFromIndex(idx))
.Where(i => i != null);
}
}
}
112 changes: 112 additions & 0 deletions Microsoft.Toolkit.Uwp.UI.Controls/BladeView/BladeViewAutomationPeer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// 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.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.Custom;
}

/// <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 = base.GetNameCore();
if (!string.IsNullOrEmpty(name))
{
return name;
}

if (this.OwningBladeView != null)
{
name = this.OwningBladeView.Name;
michael-hawker marked this conversation as resolved.
Show resolved Hide resolved
}

if (string.IsNullOrEmpty(name))
{
name = this.GetClassName();
}

return name;
}

/// <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;
}
}
}