Skip to content
11 changes: 11 additions & 0 deletions Microsoft.Toolkit.Uwp.UI.Controls/Expander/Expander.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
// See the LICENSE file in the project root for more information.

using System;
using Microsoft.Toolkit.Uwp.UI.Automation.Peers;
using Windows.System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation.Peers;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Input;
Expand Down Expand Up @@ -76,6 +78,15 @@ protected virtual void OnCollapsed(EventArgs args)
Collapsed?.Invoke(this, args);
}

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

private void ExpanderToggleButtonPart_KeyDown(object sender, KeyRoutedEventArgs e)
{
if (e.Key != VirtualKey.Enter)
Expand Down
116 changes: 116 additions & 0 deletions Microsoft.Toolkit.Uwp.UI.Controls/Expander/ExpanderAutomationPeer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// 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 Windows.UI.Xaml.Automation;
using Windows.UI.Xaml.Automation.Peers;
using Windows.UI.Xaml.Automation.Provider;

namespace Microsoft.Toolkit.Uwp.UI.Automation.Peers
{
/// <summary>
/// Defines a framework element automation peer for the <see cref="Expander"/> control.
/// </summary>
public class ExpanderAutomationPeer : FrameworkElementAutomationPeer, IToggleProvider
Copy link
Member

Choose a reason for hiding this comment

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

@jamesmcroft I missed we should have used the IExpandCollapseProvider in addition or instead of maybe? Thoughts?

Copy link
Member Author

Choose a reason for hiding this comment

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

Let me take a look, I don't see why not though. Would you want this to be inclusive of IToggleProvider or in favor of?

Copy link
Member

Choose a reason for hiding this comment

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

@jamesmcroft good question. I don't know if it's a problem to provide multiple interfaces, probably best to include both if possible? I know some other code will probably look for one over the other, so I imagine having both would allow it to be used by the most other code parts looking for certain types of peers. @chingucoding @ranjeshj any thoughts?

Would it make sense to add unit tests like in #3544 as well?

Copy link
Contributor

@marcelwgn marcelwgn Nov 10, 2020

Choose a reason for hiding this comment

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

I don't know if it's a problem to provide multiple interfaces, probably best to include both if possible?

I would argue that having both interfaces only makes sense if you expose both patterns in GetPatternCore. So at least implement what you are providing as part of GetPatternCore. For what it's worth, the WinUI expander control only specifies the ExpandCollapsePattern, so I am inclined to say that that pattern/interface is sufficient.

Would it make sense to add unit tests like in #3544 as well?

Yes, I think testing that peer and the exposed functions of the peer should be done.

Copy link
Contributor

Choose a reason for hiding this comment

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

You can have multiple patterns supported for sure. ExpandCollapse pattern made sense for Expander.

Copy link
Member

Choose a reason for hiding this comment

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

@jamesmcroft if you've got some cycles still to continue helping with this, mind submitting a follow-on PR with the tweaks? Thanks!

Copy link
Member Author

Choose a reason for hiding this comment

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

@michael-hawker I'll get another PR open for these changes 😄

{
/// <summary>
/// Initializes a new instance of the <see cref="ExpanderAutomationPeer"/> class.
/// </summary>
/// <param name="owner">
/// The <see cref="Expander" /> that is associated with this <see cref="T:Windows.UI.Xaml.Automation.Peers.ExpanderAutomationPeer" />.
/// </param>
public ExpanderAutomationPeer(Expander owner)
: base(owner)
{
}

/// <summary>Gets the toggle state of the control.</summary>
/// <returns>The toggle state of the control, as a value of the enumeration.</returns>
public ToggleState ToggleState => OwningExpander.IsExpanded ? ToggleState.On : ToggleState.Off;

private Expander OwningExpander
{
get
{
return Owner as Expander;
}
}

/// <summary>Cycles through the toggle states of a control.</summary>
public void Toggle()
{
if (!IsEnabled())
{
throw new ElementNotEnabledException();
}

OwningExpander.IsExpanded = !OwningExpander.IsExpanded;
}

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

if (this.OwningExpander != null)
{
name = this.OwningExpander.Name;
}

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

return name;
}

/// <summary>
/// Gets the control pattern that is associated with the specified Windows.UI.Xaml.Automation.Peers.PatternInterface.
/// </summary>
/// <param name="patternInterface">A value from the Windows.UI.Xaml.Automation.Peers.PatternInterface enumeration.</param>
/// <returns>The object that supports the specified pattern, or null if unsupported.</returns>
protected override object GetPatternCore(PatternInterface patternInterface)
{
switch (patternInterface)
{
case PatternInterface.Toggle:
return this;
}

return base.GetPatternCore(patternInterface);
}
}
}