diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/BladeView/BladeItem.Properties.cs b/Microsoft.Toolkit.Uwp.UI.Controls/BladeView/BladeItem.Properties.cs index debff7e8596..72d44b730a5 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/BladeView/BladeItem.Properties.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/BladeView/BladeItem.Properties.cs @@ -39,6 +39,8 @@ public partial class BladeItem /// public static readonly DependencyProperty CloseButtonForegroundProperty = DependencyProperty.Register(nameof(CloseButtonForeground), typeof(Brush), typeof(BladeItem), new PropertyMetadata(new SolidColorBrush(Colors.Black))); + private WeakReference _parentBladeView; + /// /// Gets or sets the foreground color of the close button /// @@ -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(value); + } + private static void IsOpenChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) { BladeItem bladeItem = (BladeItem)dependencyObject; diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/BladeView/BladeItem.cs b/Microsoft.Toolkit.Uwp.UI.Controls/BladeView/BladeItem.cs index 79373541841..21202d4d9fe 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/BladeView/BladeItem.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/BladeView/BladeItem.cs @@ -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 @@ -92,6 +94,15 @@ protected override void OnCollapsed(EventArgs args) } } + /// + /// Creates AutomationPeer () + /// + /// An automation peer for this . + protected override AutomationPeer OnCreateAutomationPeer() + { + return new BladeItemAutomationPeer(this); + } + private void OnSizeChanged(object sender, SizeChangedEventArgs sizeChangedEventArgs) { if (IsExpanded) diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/BladeView/BladeItemAutomationPeer.cs b/Microsoft.Toolkit.Uwp.UI.Controls/BladeView/BladeItemAutomationPeer.cs new file mode 100644 index 00000000000..57033555a37 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls/BladeView/BladeItemAutomationPeer.cs @@ -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 +{ + /// + /// Defines a framework element automation peer for the . + /// + public class BladeItemAutomationPeer : FrameworkElementAutomationPeer + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The that is associated with this . + /// + public BladeItemAutomationPeer(BladeItem owner) + : base(owner) + { + } + + private BladeItem OwnerBladeItem + { + get { return this.Owner as BladeItem; } + } + + /// + /// Gets the control type for the element that is associated with the UI Automation peer. + /// + /// The control type. + protected override AutomationControlType GetAutomationControlTypeCore() + { + return AutomationControlType.ListItem; + } + + /// + /// Called by GetClassName that gets a human readable name that, in addition to AutomationControlType, + /// differentiates the control represented by this AutomationPeer. + /// + /// The string that contains the name. + protected override string GetClassNameCore() + { + return Owner.GetType().Name; + } + + /// + /// Called by GetName. + /// + /// + /// 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 + /// + 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(); + if (textBlock != null) + { + return textBlock.Text; + } + + name = base.GetNameCore(); + if (!string.IsNullOrEmpty(name)) + { + return name; + } + + return string.Empty; + } + + /// + /// Called by GetAutomationId that gets the **AutomationId** of the element that is associated with the automation peer. + /// + /// + /// The string that contains the automation ID. + /// + protected override string GetAutomationIdCore() + { + string automationId = base.GetAutomationIdCore(); + if (!string.IsNullOrEmpty(automationId)) + { + return automationId; + } + + if (this.OwnerBladeItem != null) + { + return this.GetNameCore(); + } + + return string.Empty; + } + + /// + /// Returns the size of the set where the element that is associated with the automation peer is located. + /// + /// + /// The size of the set. + /// + 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; + } + + /// + /// Returns the ordinal position in the set for the element that is associated with the automation peer. + /// + /// + /// The ordinal position in the set. + /// + 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; + } + } +} \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/BladeView/BladeView.cs b/Microsoft.Toolkit.Uwp.UI.Controls/BladeView/BladeView.cs index bf0ff71639e..e2590010e48 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/BladeView/BladeView.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/BladeView/BladeView.cs @@ -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 @@ -65,6 +67,7 @@ protected override void PrepareContainerForItemOverride(DependencyObject element if (blade != null) { blade.VisibilityChanged += BladeOnVisibilityChanged; + blade.ParentBladeView = this; } base.PrepareContainerForItemOverride(element, item); @@ -83,6 +86,15 @@ protected override void ClearContainerForItemOverride(DependencyObject element, base.ClearContainerForItemOverride(element, item); } + /// + /// Creates AutomationPeer () + /// + /// An automation peer for this . + protected override AutomationPeer OnCreateAutomationPeer() + { + return new BladeViewAutomationPeer(this); + } + private void CycleBlades() { ActiveBlades = new ObservableCollection(); diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/BladeView/BladeViewAutomationPeer.cs b/Microsoft.Toolkit.Uwp.UI.Controls/BladeView/BladeViewAutomationPeer.cs new file mode 100644 index 00000000000..d2f8e6cadfa --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls/BladeView/BladeViewAutomationPeer.cs @@ -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 +{ + /// + /// Defines a framework element automation peer for the control. + /// + public class BladeViewAutomationPeer : ItemsControlAutomationPeer + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The that is associated with this . + /// + public BladeViewAutomationPeer(BladeView owner) + : base(owner) + { + } + + private BladeView OwningBladeView + { + get + { + return Owner as BladeView; + } + } + + /// + /// Gets the control type for the element that is associated with the UI Automation peer. + /// + /// The control type. + protected override AutomationControlType GetAutomationControlTypeCore() + { + return AutomationControlType.List; + } + + /// + /// Called by GetClassName that gets a human readable name that, in addition to AutomationControlType, + /// differentiates the control represented by this AutomationPeer. + /// + /// The string that contains the name. + protected override string GetClassNameCore() + { + return Owner.GetType().Name; + } + + /// + /// Called by GetName. + /// + /// + /// 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 + /// + 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; + } + + /// + /// Gets the collection of elements that are represented in the UI Automation tree as immediate + /// child elements of the automation peer. + /// + /// The children elements. + protected override IList GetChildrenCore() + { + BladeView owner = OwningBladeView; + + ItemCollection items = owner.Items; + if (items.Count <= 0) + { + return null; + } + + List peers = new List(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; + } + } +} diff --git a/UnitTests/UnitTests.UWP/UI/Controls/Test_BladeView.cs b/UnitTests/UnitTests.UWP/UI/Controls/Test_BladeView.cs new file mode 100644 index 00000000000..fa32042e85a --- /dev/null +++ b/UnitTests/UnitTests.UWP/UI/Controls/Test_BladeView.cs @@ -0,0 +1,36 @@ +// 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 Windows.UI.Xaml.Automation; +using Microsoft.Toolkit.Uwp.UI.Controls; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer; +using Windows.UI.Xaml.Automation.Peers; +using Microsoft.Toolkit.Uwp.UI.Automation.Peers; + +namespace UnitTests.UWP.UI.Controls +{ + [TestClass] + [TestCategory("Test_BladeView")] + public class Test_BladeView + { + [UITestMethod] + public void ShouldConfigureBladeViewAutomationPeer() + { + const string automationName = "MyAutomationBlades"; + const string name = "MyBlades"; + + var bladeView = new BladeView(); + var bladeViewAutomationPeer = FrameworkElementAutomationPeer.CreatePeerForElement(bladeView) as BladeViewAutomationPeer; + + Assert.IsNotNull(bladeViewAutomationPeer, "Verify that the AutomationPeer is BladeViewAutomationPeer."); + + bladeView.Name = name; + Assert.IsTrue(bladeViewAutomationPeer.GetName().Contains(name), "Verify that the UIA name contains the given Name of the BladeView."); + + bladeView.SetValue(AutomationProperties.NameProperty, automationName); + Assert.IsTrue(bladeViewAutomationPeer.GetName().Contains(automationName), "Verify that the UIA name contains the given AutomationProperties.Name of the BladeView."); + } + } +} \ No newline at end of file diff --git a/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj b/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj index a05bbb4e8e3..4f24302dafc 100644 --- a/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj +++ b/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj @@ -179,6 +179,7 @@ +