Skip to content

Commit

Permalink
Merge pull request unoplatform#14257 from ramezgerges/expander_align_…
Browse files Browse the repository at this point in the history
…winui

chore: align Expander with WinUI
  • Loading branch information
MartinZikmund authored Nov 14, 2023
2 parents 184b680 + 78a8eb9 commit 1c4a60e
Show file tree
Hide file tree
Showing 4 changed files with 369 additions and 46 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

// MUX Reference Expander/APITests/ExpanderTests.cpp, tag winui3/release/1.4.2

using Windows.UI.Xaml.Automation;
using Windows.UI.Xaml.Automation.Peers;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Markup;
using Windows.UI.Xaml.Media;
using Common;
#if !HAS_UNO_WINUI
using Microsoft.UI.Xaml.Controls;
#endif
using MUXControlsTestApp.Utilities;
using Uno.UI.RuntimeTests.Helpers;

namespace Microsoft.UI.Xaml.Tests.MUXControls.ApiTests
{
[TestClass]
public class ExpanderTests : MUXApiTestBase
{
[TestMethod]
public void ExpanderAutomationPeerTest()
{
RunOnUIThread.Execute(() =>
{
// Uno specific: the control is fluent only
using var _ = StyleHelper.UseFluentStyles();
var root = (StackPanel)XamlReader.Load(
@"<StackPanel xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
xmlns:primitives='using:Microsoft.UI.Xaml.Controls.Primitives'
xmlns:controls='using:Microsoft.UI.Xaml.Controls'>
<controls:Expander x:Name ='ExpandedExpander' AutomationProperties.Name='ExpandedExpander' IsExpanded='True' Margin='12' HorizontalAlignment='Left'>
<controls:Expander.Header>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width='80'/>
</Grid.ColumnDefinitions>
<StackPanel Margin='0,14,0,16'>
<TextBlock AutomationProperties.Name='test' Text='This expander is expanded by default.' Margin='0,0,0,4' />
<TextBlock Text='This is the second line of text.' />
</StackPanel>
<ToggleSwitch Grid.Column='1'/>
</Grid>
</controls:Expander.Header>
<Button AutomationProperties.AutomationId = 'ExpandedExpanderContent'> Content </Button>
</controls:Expander>
</StackPanel>");
Content = root;
Content.UpdateLayout();
var expander = VisualTreeHelper.GetChild(root, 0) as Expander;
expander.IsExpanded = true;
Content.UpdateLayout();
var grid = VisualTreeHelper.GetChild(expander, 0);
var toggleButton = VisualTreeHelper.GetChild(grid, 0);
var toggleButtonGrid = VisualTreeHelper.GetChild(toggleButton, 0);
var contentPresenter = VisualTreeHelper.GetChild(toggleButtonGrid, 0);
var grid2 = VisualTreeHelper.GetChild(contentPresenter, 0);
var stackPanel = VisualTreeHelper.GetChild(grid2, 0);
var textBlock1 = VisualTreeHelper.GetChild(stackPanel, 0) as TextBlock;
var textBlock2 = VisualTreeHelper.GetChild(stackPanel, 1) as TextBlock;
var toggleSwitch = VisualTreeHelper.GetChild(grid2, 1) as ToggleSwitch;
var border = VisualTreeHelper.GetChild(grid, 1);
var expanderContentBorder = VisualTreeHelper.GetChild(border, 0);
var expanderContentContentPresenter = VisualTreeHelper.GetChild(expanderContentBorder, 0);
var button = VisualTreeHelper.GetChild(expanderContentContentPresenter, 0) as Button;
// https://github.com/unoplatform/uno/issues/14256
// Verify.AreEqual("ExpandedExpander", AutomationProperties.GetName(expander));
// Verify ExpandedExpander header content are included in the accessibility tree
Verify.AreEqual(AutomationProperties.GetAccessibilityView(textBlock1), AccessibilityView.Content);
Verify.AreEqual(AutomationProperties.GetAccessibilityView(textBlock2), AccessibilityView.Content);
Verify.AreEqual(AutomationProperties.GetAccessibilityView(toggleSwitch), AccessibilityView.Content);
// Verify ExpandedExpander content is included in the accessibility tree
Verify.AreEqual(AutomationProperties.GetAccessibilityView(button), AccessibilityView.Content);
expander.IsExpanded = false;
Content.UpdateLayout();
// Verify ExpandedExpander content is not included in the accessibility tree and not readable once collapsed
Verify.AreNotEqual(AutomationProperties.GetAccessibilityView(button), AccessibilityView.Raw);
});
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
// // Copyright (c) Microsoft Corporation. All rights reserved.
// // Licensed under the MIT License. See LICENSE in the project root for license information.

// MUX Reference Expander/InteractionTests/ExpanderTests.cpp, tag winui3/release/1.4.2

// using System;
// using Common;
// using Windows.UI.Xaml.Tests.MUXControls.InteractionTests.Infra;
// using Windows.UI.Xaml.Tests.MUXControls.InteractionTests.Common;
// using System.Collections.Generic;
// using Windows.Foundation.Metadata;
//
// #if USING_TAEF
// using WEX.TestExecution;
// using WEX.TestExecution.Markup;
// using WEX.Logging.Interop;
// #else
// using Microsoft.VisualStudio.TestTools.UnitTesting;
// using Microsoft.VisualStudio.TestTools.UnitTesting.Logging;
// #endif
//
// using Microsoft.Windows.Apps.Test.Automation;
// using Microsoft.Windows.Apps.Test.Foundation;
// using Microsoft.Windows.Apps.Test.Foundation.Controls;
// using Microsoft.Windows.Apps.Test.Foundation.Patterns;
// using Microsoft.Windows.Apps.Test.Foundation.Waiters;
// using MUXTestInfra.Shared.Infra;
//
// namespace Windows.UI.Xaml.Tests.MUXControls.InteractionTests
// {
// public class Expander : UIObject, IExpandCollapse
// {
// public Expander(UIObject uiObject)
// : base(uiObject)
// {
// this.Initialize();
// }
//
// private void Initialize()
// {
// _expandCollapsePattern = new ExpandCollapseImplementation(this);
// }
//
// public void ExpandAndWait()
// {
// using (var waiter = GetExpandedWaiter())
// {
// Expand();
// waiter.Wait();
// }
//
// Wait.ForIdle();
// }
//
// public void CollapseAndWait()
// {
// using (var waiter = GetCollapsedWaiter())
// {
// Collapse();
// waiter.Wait();
// }
//
// Wait.ForIdle();
// }
//
// public void Expand()
// {
// _expandCollapsePattern.Expand();
// }
//
// public void Collapse()
// {
// _expandCollapsePattern.Collapse();
// }
//
// public UIEventWaiter GetExpandedWaiter()
// {
// return _expandCollapsePattern.GetExpandedWaiter();
// }
//
// public UIEventWaiter GetCollapsedWaiter()
// {
// return _expandCollapsePattern.GetCollapsedWaiter();
// }
//
// public ExpandCollapseState ExpandCollapseState
// {
// get { return _expandCollapsePattern.ExpandCollapseState; }
// }
//
// new public static IFactory<Expander> Factory
// {
// get
// {
// if (null == Expander._factory)
// {
// Expander._factory = new ExpanderFactory();
// }
// return Expander._factory;
// }
// }
//
// private IExpandCollapse _expandCollapsePattern;
// private static IFactory<Expander> _factory = null;
// private class ExpanderFactory : IFactory<Expander>
// {
// public Expander Create(UIObject element)
// {
// return new Expander(element);
// }
// }
// }
//
// [TestClass]
// public class ExpanderTests
// {
// [ClassInitialize]
// [TestProperty("RunAs", "User")]
// [TestProperty("Classification", "Integration")]
// [TestProperty("Platform", "Any")]
// [TestProperty("MUXControlsTestSuite", "SuiteB")]
// public static void ClassInitialize(TestContext testContext)
// {
// TestEnvironment.Initialize(testContext);
// }
//
// public void TestCleanup()
// {
// TestCleanupHelper.Cleanup();
// }
//
// [TestMethod]
// public void VerifyAxeScanPasses()
// {
// using (var setup = new TestSetupHelper("Expander-Axe"))
// {
// AxeTestHelper.TestForAxeIssues();
// }
// }
//
// [TestMethod]
// public void ExpandCollapseAutomationTests()
// {
// using (var setup = new TestSetupHelper("Expander Tests"))
// {
// Expander expander = FindElement.ByName<Expander>("ExpandedExpander");
// expander.SetFocus();
// Wait.ForIdle();
//
// Log.Comment("Collapse using keyboard space key.");
// KeyboardHelper.PressKey(Key.Space);
// Verify.AreEqual(expander.ExpandCollapseState, ExpandCollapseState.Collapsed);
//
// Log.Comment("Expand using keyboard space key.");
// KeyboardHelper.PressKey(Key.Space);
// Verify.AreEqual(expander.ExpandCollapseState, ExpandCollapseState.Expanded);
//
// Log.Comment("Collapse by clicking.");
// expander.Click();
// Verify.AreEqual(expander.ExpandCollapseState, ExpandCollapseState.Collapsed);
//
// Log.Comment("Expand by clicking.");
// expander.Click();
// Verify.AreEqual(expander.ExpandCollapseState, ExpandCollapseState.Expanded);
//
// Log.Comment("Collapse using UIA ExpandCollapse pattern");
// expander.CollapseAndWait();
// Verify.AreEqual(expander.ExpandCollapseState, ExpandCollapseState.Collapsed);
//
// Log.Comment("Expand using UIA ExpandCollapse pattern");
// expander.ExpandAndWait();
// Verify.AreEqual(expander.ExpandCollapseState, ExpandCollapseState.Expanded);
// }
// }
//
// [TestMethod]
// public void AutomationPeerTest()
// {
// using (var setup = new TestSetupHelper("Expander Tests"))
// {
// Expander expander = FindElement.ByName<Expander>("ExpanderWithToggleSwitch");
// expander.SetFocus();
// Wait.ForIdle();
//
// // Verify ExpandedExpander header content AutomationProperties.Name properties are set
// VerifyElement.Found("This expander with ToggleSwitch is expanded by default.", FindBy.Name);
// VerifyElement.Found("This is the second line of text.", FindBy.Name);
// VerifyElement.Found("SettingsToggleSwitch", FindBy.Name);
//
// // Verify ExpandedExpander content AutomationProperties.Name property is set
// VerifyElement.Found("ExpanderWithToggleSwitch Content", FindBy.Name);
//
// Log.Comment("Collapse using keyboard space key.");
// KeyboardHelper.PressKey(Key.Space);
// Verify.AreEqual(expander.ExpandCollapseState, ExpandCollapseState.Collapsed);
//
// // Verify ExpandedExpander content AutomationProperties.Name property is not visible once collapsed
// VerifyElement.NotFound("ExpanderWithToggleSwitch Content", FindBy.Name);
// }
// }
// }
// }
35 changes: 18 additions & 17 deletions src/Uno.UI/Microsoft/UI/Xaml/Controls/Expander/Expander.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
using System.Numerics;
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

// MUX Reference Expander.cpp, tag winui3/release/1.4.2

using System.Numerics;
using Uno.Disposables;
using Windows.Foundation;
using Windows.UI.Xaml;
Expand Down Expand Up @@ -26,21 +31,16 @@ public Expander()

SetValue(TemplateSettingsProperty, new ExpanderTemplateSettings());

#if HAS_UNO
// Uno specific: we might leak on iOS: https://github.com/unoplatform/uno/pull/14257#discussion_r1381585268
Loaded += Expander_Loaded;
Unloaded += Expander_Unloaded;
#endif
}

protected override AutomationPeer OnCreateAutomationPeer() => new ExpanderAutomationPeer(this);

protected override void OnApplyTemplate()
{
// Uno specific: Added to dispose event handlers
_eventSubscriptions.Disposable = null;
var registrations = new CompositeDisposable();

if (GetTemplateChild<Control>(c_expanderHeader) is ToggleButton toggleButton)
if (GetTemplateChild<Control>(c_expanderHeader) is Control toggleButton)
{
// We will do 2 things with the toggle button's peer:
// 1. Set the events source of the toggle button peer to
Expand Down Expand Up @@ -75,6 +75,11 @@ protected override void OnApplyTemplate()
}
}

// Uno specific: Added to dispose event handlers
_eventSubscriptions.Disposable = null;
var registrations = new CompositeDisposable();
_eventSubscriptions.Disposable = registrations;

if (GetTemplateChild<Border>(c_expanderContentClip) is Border expanderContentClip)
{
// TODO Uno specific: The Composition clipping APIs are currently unsupported,
Expand All @@ -97,9 +102,6 @@ protected override void OnApplyTemplate()

UpdateExpandState(false);
UpdateExpandDirection(false);

// Uno specific: Added to dispose event handlers
_eventSubscriptions.Disposable = registrations;
}

#if HAS_UNO
Expand All @@ -124,10 +126,10 @@ private void OnContentSizeChanged(object sender, SizeChangedEventArgs args)
}

private void RaiseExpandingEvent(Expander container) =>
Expanding?.Invoke(this, new ExpanderExpandingEventArgs()); // Uno specific: We won't use null for args like WinUI
Expanding?.Invoke(this, null);

private void RaiseCollapsedEvent(Expander container) =>
Collapsed?.Invoke(this, new ExpanderCollapsedEventArgs()); // Uno specific: We won't use null for args like WinUI
Collapsed?.Invoke(this, null);

private void OnIsExpandedPropertyChanged(DependencyPropertyChangedEventArgs args)
{
Expand Down Expand Up @@ -205,13 +207,13 @@ private void UpdateExpandState(bool useTransitions)
var expanderPeer = peer as ExpanderAutomationPeer;
expanderPeer?.RaiseExpandCollapseAutomationEvent(
isExpanded ?
ExpandCollapseState.Expanded :
ExpandCollapseState.Collapsed
ExpandCollapseState.Expanded :
ExpandCollapseState.Collapsed
);
}
}

#if HAS_UNO // Uno specific: We need to ensure events are subscribed/unsubscribed on load/unload to avoid memory leaks.
// Uno specific: We need to ensure events are subscribed/unsubscribed on load/unload to avoid memory leaks.
private void Expander_Loaded(object sender, RoutedEventArgs e)
{
if (_eventSubscriptions.Disposable is null)
Expand All @@ -221,5 +223,4 @@ private void Expander_Loaded(object sender, RoutedEventArgs e)
}

private void Expander_Unloaded(object sender, RoutedEventArgs e) => _eventSubscriptions.Disposable = null;
#endif
}
Loading

0 comments on commit 1c4a60e

Please sign in to comment.