Skip to content

Commit

Permalink
CommandBarFlyoutCommandBar fix - respond to size changes (#6868)
Browse files Browse the repository at this point in the history
  • Loading branch information
RBrid authored Mar 23, 2022
1 parent bf6a4d2 commit 573e4a2
Show file tree
Hide file tree
Showing 6 changed files with 376 additions and 18 deletions.
26 changes: 15 additions & 11 deletions dev/CommandBarFlyout/CommandBarFlyoutCommandBar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,20 @@ CommandBarFlyoutCommandBar::CommandBarFlyoutCommandBar()
[this](auto const&, auto const&)
{
#ifdef _DEBUG
COMMANDBARFLYOUT_TRACE_VERBOSE(*this, TRACE_MSG_METH_STR, METH_NAME, this, L"SizedChanged");
COMMANDBARFLYOUT_TRACE_VERBOSE(*this, TRACE_MSG_METH_STR, METH_NAME, this, L"SizeChanged");
#endif

UpdateUI(!m_commandBarFlyoutIsOpening);
UpdateUI(!m_commandBarFlyoutIsOpening, true /*isForSizeChange*/);
}
});

Closing({
[this](auto const&, auto const&)
{
#ifdef _DEBUG
COMMANDBARFLYOUT_TRACE_VERBOSE(*this, TRACE_MSG_METH_STR, METH_NAME, this, L"Closing");
#endif

if (auto owningFlyout = m_owningFlyout.get())
{
if (owningFlyout.AlwaysExpanded())
Expand Down Expand Up @@ -283,7 +287,7 @@ void CommandBarFlyoutCommandBar::AttachEventHandlers()
#endif

m_secondaryItemsRootSized = true;
UpdateUI(!m_commandBarFlyoutIsOpening);
UpdateUI(!m_commandBarFlyoutIsOpening, true /*isForSizeChange*/);
}
});

Expand Down Expand Up @@ -499,19 +503,19 @@ void CommandBarFlyoutCommandBar::UpdateFlowsFromAndFlowsTo()
}

void CommandBarFlyoutCommandBar::UpdateUI(
bool useTransitions, bool isForCommandBarElementDependencyPropertyChange)
bool useTransitions, bool isForSizeChange)
{
COMMANDBARFLYOUT_TRACE_VERBOSE(*this, TRACE_MSG_METH_INT_INT, METH_NAME, this, useTransitions, isForCommandBarElementDependencyPropertyChange);
COMMANDBARFLYOUT_TRACE_VERBOSE(*this, TRACE_MSG_METH_INT_INT, METH_NAME, this, useTransitions, isForSizeChange);

UpdateTemplateSettings();
UpdateVisualState(useTransitions, isForCommandBarElementDependencyPropertyChange);
UpdateVisualState(useTransitions, isForSizeChange);

UpdateProjectedShadow();
}

void CommandBarFlyoutCommandBar::UpdateVisualState(
bool useTransitions,
bool isForCommandBarElementDependencyPropertyChange)
bool isForSizeChange)
{
if (IsOpen())
{
Expand Down Expand Up @@ -575,14 +579,14 @@ void CommandBarFlyoutCommandBar::UpdateVisualState(
}
}

if (isForCommandBarElementDependencyPropertyChange)
if (isForSizeChange)
{
// UpdateVisualState is called as a result of a secondary command bar element dependency property change. This CommandBarFlyoutCommandBar is already open
// UpdateVisualState is called as a result of a size change (for instance caused by a secondary command bar element dependency property change). This CommandBarFlyoutCommandBar is already open
// and expanded. Jump to the Collapsed and back to ExpandedUp/ExpandedDown state to apply all refreshed CommandBarFlyoutCommandBarTemplateSettings values.
winrt::VisualStateManager::GoToState(*this, L"Collapsed", false);
}

winrt::VisualStateManager::GoToState(*this, shouldExpandUp ? L"ExpandedUp" : L"ExpandedDown", useTransitions && !isForCommandBarElementDependencyPropertyChange);
winrt::VisualStateManager::GoToState(*this, shouldExpandUp ? L"ExpandedUp" : L"ExpandedDown", useTransitions && !isForSizeChange);

// Union of AvailableCommandsStates and ExpansionStates
bool hasPrimaryCommands = (PrimaryCommands().Size() != 0);
Expand Down Expand Up @@ -1404,6 +1408,6 @@ void CommandBarFlyoutCommandBar::OnCommandBarElementDependencyPropertyChanged()
// Only refresh the UI when the CommandBarFlyoutCommandBar is already open since it will be refreshed anyways in the event it gets opened.
if (IsOpen())
{
UpdateUI(!m_commandBarFlyoutIsOpening, true /*isForCommandBarElementDependencyPropertyChange*/);
UpdateUI(!m_commandBarFlyoutIsOpening, true /*isForSizeChange*/);
}
}
4 changes: 2 additions & 2 deletions dev/CommandBarFlyout/CommandBarFlyoutCommandBar.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ class CommandBarFlyoutCommandBar :
void DetachEventHandlers();

void UpdateFlowsFromAndFlowsTo();
void UpdateUI(bool useTransitions = true, bool isForCommandBarElementDependencyPropertyChange = false);
void UpdateVisualState(bool useTransitions, bool isForCommandBarElementDependencyPropertyChange = false);
void UpdateUI(bool useTransitions = true, bool isForSizeChange = false);
void UpdateVisualState(bool useTransitions, bool isForSizeChange = false);
void UpdateTemplateSettings();
void EnsureAutomationSetCountAndPosition();
void EnsureLocalizedControlTypes();
Expand Down
168 changes: 168 additions & 0 deletions dev/CommandBarFlyout/InteractionTests/CommandBarFlyoutTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1005,6 +1005,174 @@ public void VerifyDynamicSecondaryCommandLabel()
}
}

[TestMethod]
public void VerifyDynamicSecondaryCommandVisibility()
{
if (PlatformConfiguration.IsOSVersionLessThan(OSVersion.Redstone2))
{
Log.Warning("Test is disabled pre-RS2 because CommandBarFlyout is not supported pre-RS2");
return;
}

using (var setup = new CommandBarFlyoutTestSetupHelper())
{
Log.Comment("Retrieving FlyoutTarget6");
Button showCommandBarFlyoutButton = FindElement.ByName<Button>("Show CommandBarFlyout with no primary commands");

Log.Comment("Retrieving IsFlyoutOpenCheckBox");
ToggleButton isFlyoutOpenCheckBox = FindElement.ById<ToggleButton>("IsFlyoutOpenCheckBox");

Log.Comment("Retrieving UseSecondaryCommandDynamicVisibilityCheckBox");
ToggleButton useSecondaryCommandDynamicVisibilityCheckBox = FindElement.ById<ToggleButton>("UseSecondaryCommandDynamicVisibilityCheckBox");

Log.Comment("SecondaryCommandDynamicVisibilityChangedCheckBox");
ToggleButton secondaryCommandDynamicVisibilityChangedCheckBox = FindElement.ById<ToggleButton>("SecondaryCommandDynamicVisibilityChangedCheckBox");

Log.Comment("Retrieving DynamicVisibilityTimerIntervalTextBox");
Edit dynamicVisibilityTimerIntervalTextBox = new Edit(FindElement.ById("DynamicVisibilityTimerIntervalTextBox"));

Log.Comment("Retrieving DynamicVisibilityChangeCountTextBox");
Edit dynamicVisibilityChangeCountTextBox = new Edit(FindElement.ById("DynamicVisibilityChangeCountTextBox"));

Verify.AreEqual(ToggleState.Off, isFlyoutOpenCheckBox.ToggleState);

Log.Comment("Change the fifth command bar element's Visibility property asynchronously after the command bar is opened");
useSecondaryCommandDynamicVisibilityCheckBox.Check();

Log.Comment("Setting DynamicVisibilityTimerIntervalTextBox to 1s");
dynamicVisibilityTimerIntervalTextBox.SetValue("1000");

Log.Comment("Setting DynamicVisibilityChangeCountTextBox to 1 single change");
dynamicVisibilityChangeCountTextBox.SetValue("1");
Wait.ForIdle();

Verify.AreEqual(ToggleState.Off, secondaryCommandDynamicVisibilityChangedCheckBox.ToggleState);

Log.Comment("Invoking button 'Show CommandBarFlyout with no primary commands' to show the Flyout6 command bar.");
showCommandBarFlyoutButton.Invoke();
Wait.ForIdle();
Verify.AreEqual(ToggleState.On, isFlyoutOpenCheckBox.ToggleState);

FocusHelper.SetFocus(FindElement.ById("UndoButton6"));

Button undoButton6 = FindElement.ById<Button>("UndoButton6");
Verify.IsNotNull(undoButton6);

UIObject commandBarElementsContainer = undoButton6.Parent;
Verify.IsNotNull(commandBarElementsContainer);

Rectangle initialBoundingRectangle = commandBarElementsContainer.BoundingRectangle;

Log.Comment("Initial commandBarElementsContainer.BoundingRectangle.Width=" + initialBoundingRectangle.Width);
Log.Comment("Initial commandBarElementsContainer.BoundingRectangle.Height=" + initialBoundingRectangle.Height);

Verify.AreEqual(ToggleState.Off, secondaryCommandDynamicVisibilityChangedCheckBox.ToggleState);

Log.Comment("Waiting for SecondaryCommandDynamicVisibilityChangedCheckBox becoming checked indicating the asynchronous Visibility property change occurred");
secondaryCommandDynamicVisibilityChangedCheckBox.GetToggledWaiter().Wait();
Wait.ForIdle();

Rectangle finalBoundingRectangle = commandBarElementsContainer.BoundingRectangle;

Log.Comment("Final commandBarElementsContainer.BoundingRectangle.Width=" + finalBoundingRectangle.Width);
Log.Comment("Final commandBarElementsContainer.BoundingRectangle.Height=" + finalBoundingRectangle.Height);

Log.Comment("Hitting Escape key to close the command bar.");
KeyboardHelper.PressKey(Key.Escape);
Wait.ForIdle();

Verify.AreEqual(ToggleState.Off, isFlyoutOpenCheckBox.ToggleState);

Log.Comment("Verifying the command bar flyout width and height were increased to accommodate the new AppBarButton.");
Verify.IsGreaterThan(finalBoundingRectangle.Width, initialBoundingRectangle.Width);
Verify.IsGreaterThan(finalBoundingRectangle.Height, initialBoundingRectangle.Height);
}
}

[TestMethod]
public void VerifyDynamicOverflowContentRootWidth()
{
if (PlatformConfiguration.IsOSVersionLessThan(OSVersion.Redstone2))
{
Log.Warning("Test is disabled pre-RS2 because CommandBarFlyout is not supported pre-RS2");
return;
}

using (var setup = new CommandBarFlyoutTestSetupHelper())
{
Log.Comment("Retrieving FlyoutTarget6");
Button showCommandBarFlyoutButton = FindElement.ByName<Button>("Show CommandBarFlyout with no primary commands");

Log.Comment("Retrieving IsFlyoutOpenCheckBox");
ToggleButton isFlyoutOpenCheckBox = FindElement.ById<ToggleButton>("IsFlyoutOpenCheckBox");

Log.Comment("Retrieving UseOverflowContentRootDynamicWidthCheckBox");
ToggleButton useOverflowContentRootDynamicWidthCheckBox = FindElement.ById<ToggleButton>("UseOverflowContentRootDynamicWidthCheckBox");

Log.Comment("OverflowContentRootDynamicWidthChangedCheckBox");
ToggleButton overflowContentRootDynamicWidthChangedCheckBox = FindElement.ById<ToggleButton>("OverflowContentRootDynamicWidthChangedCheckBox");

Log.Comment("Retrieving DynamicWidthTimerIntervalTextBox");
Edit dynamicWidthTimerIntervalTextBox = new Edit(FindElement.ById("DynamicWidthTimerIntervalTextBox"));

Log.Comment("Retrieving DynamicWidthChangeCountTextBox");
Edit dynamicWidthChangeCountTextBox = new Edit(FindElement.ById("DynamicWidthChangeCountTextBox"));

Verify.AreEqual(ToggleState.Off, isFlyoutOpenCheckBox.ToggleState);

Log.Comment("Change the fifth command bar element's Visibility property asynchronously after the command bar is opened");
useOverflowContentRootDynamicWidthCheckBox.Check();

Log.Comment("Setting DynamicWidthTimerIntervalTextBox to 1s");
dynamicWidthTimerIntervalTextBox.SetValue("1000");

Log.Comment("Setting DynamicWidthChangeCountTextBox to 1 single change");
dynamicWidthChangeCountTextBox.SetValue("1");
Wait.ForIdle();

Verify.AreEqual(ToggleState.Off, overflowContentRootDynamicWidthChangedCheckBox.ToggleState);

Log.Comment("Invoking button 'Show CommandBarFlyout with no primary commands' to show the Flyout6 command bar.");
showCommandBarFlyoutButton.Invoke();
Wait.ForIdle();
Verify.AreEqual(ToggleState.On, isFlyoutOpenCheckBox.ToggleState);

FocusHelper.SetFocus(FindElement.ById("UndoButton6"));

Button undoButton6 = FindElement.ById<Button>("UndoButton6");
Verify.IsNotNull(undoButton6);

UIObject commandBarElementsContainer = undoButton6.Parent;
Verify.IsNotNull(commandBarElementsContainer);

Rectangle initialBoundingRectangle = commandBarElementsContainer.BoundingRectangle;

Log.Comment("Initial commandBarElementsContainer.BoundingRectangle.Width=" + initialBoundingRectangle.Width);
Log.Comment("Initial commandBarElementsContainer.BoundingRectangle.Height=" + initialBoundingRectangle.Height);

Verify.AreEqual(ToggleState.Off, overflowContentRootDynamicWidthChangedCheckBox.ToggleState);

Log.Comment("Waiting for OverflowContentRootDynamicWidthChangedCheckBox becoming checked indicating the asynchronous Visibility property change occurred");
overflowContentRootDynamicWidthChangedCheckBox.GetToggledWaiter().Wait();
Wait.ForIdle();

Rectangle finalBoundingRectangle = commandBarElementsContainer.BoundingRectangle;

Log.Comment("Final commandBarElementsContainer.BoundingRectangle.Width=" + finalBoundingRectangle.Width);
Log.Comment("Final commandBarElementsContainer.BoundingRectangle.Height=" + finalBoundingRectangle.Height);

Log.Comment("Hitting Escape key to close the command bar.");
KeyboardHelper.PressKey(Key.Escape);
Wait.ForIdle();

Verify.AreEqual(ToggleState.Off, isFlyoutOpenCheckBox.ToggleState);

Log.Comment("Verifying the command bar flyout width was increased to accommodate the OverflowContentRoot's larger Width.");
Verify.IsGreaterThan(finalBoundingRectangle.Width, initialBoundingRectangle.Width);
Verify.AreEqual(finalBoundingRectangle.Height, initialBoundingRectangle.Height);
}
}

[TestMethod]
public void VerifyIsFlyoutKeyboardAccessibleWithNoPrimaryCommands()
{
Expand Down
18 changes: 18 additions & 0 deletions dev/CommandBarFlyout/TestUI/CommandBarFlyoutPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@
<AppBarButton x:Name="UndoButton5" AutomationProperties.AutomationId="UndoButton5" Label="Undo" Icon="Undo" Click="OnElementClicked" />
<AppBarButton x:Name="RedoButton5" AutomationProperties.AutomationId="RedoButton5" Label="Redo" Icon="Redo" Click="OnElementClicked" />
<AppBarButton x:Name="SelectAllButton5" AutomationProperties.AutomationId="SelectAllButton5" Label="Select all" Click="OnElementClicked" />
<AppBarButton x:Name="LongLabelButton5" AutomationProperties.AutomationId="LongLabelButton5" Label="AppBarButton with long label" Visibility="Collapsed" Click="OnElementClicked" />
</muxc:CommandBarFlyout.SecondaryCommands>
</muxc:CommandBarFlyout>
<muxc:CommandBarFlyout Placement="Right" x:Name="Flyout6" AutomationProperties.AutomationId="Flyout6" Opened="OnFlyoutOpened" Closed="OnFlyoutClosed">
Expand All @@ -138,6 +139,7 @@
<AppBarButton x:Name="RedoButton6" AutomationProperties.AutomationId="RedoButton6" Label="Redo" Icon="Redo" Click="OnElementClicked" />
<AppBarButton x:Name="SelectAllButton6" AutomationProperties.AutomationId="SelectAllButton6" Label="Select all" Click="OnElementClicked" />
<AppBarToggleButton x:Name="FavoriteToggleButton6" AutomationProperties.AutomationId="FavoriteToggleButton6" Label="Favorite" Icon="Favorite" Checked="OnElementChecked" Unchecked="OnElementUnchecked" />
<AppBarButton x:Name="LongLabelButton6" AutomationProperties.AutomationId="LongLabelButton6" Label="AppBarButton with long label" Visibility="Collapsed" Click="OnElementClicked" />
</muxc:CommandBarFlyout.SecondaryCommands>
</muxc:CommandBarFlyout>
<muxc:CommandBarFlyout Placement="Right" x:Name="Flyout7" AutomationProperties.AutomationId="Flyout7" Opened="OnFlyoutOpened" Closed="OnFlyoutClosed">
Expand Down Expand Up @@ -236,6 +238,22 @@
<TextBlock Text="Change Count:" Margin="5,0,0,0" VerticalAlignment="Center"/>
<TextBox x:Name="DynamicLabelChangeCountTextBox" Text="4" Margin="5,0,0,0" AutomationProperties.AutomationId="DynamicLabelChangeCountTextBox"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="10,0,10,2">
<CheckBox x:Name="UseSecondaryCommandDynamicVisibilityCheckBox" Content="Use Secondary Command with Dynamic Visibility?" AutomationProperties.AutomationId="UseSecondaryCommandDynamicVisibilityCheckBox" />
<CheckBox x:Name="SecondaryCommandDynamicVisibilityChangedCheckBox" Content="Visibility Changed?" AutomationProperties.AutomationId="SecondaryCommandDynamicVisibilityChangedCheckBox" Margin="5,0,0,0" />
<TextBlock Text="Timer Interval (ms):" Margin="5,0,0,0" VerticalAlignment="Center"/>
<TextBox x:Name="DynamicVisibilityTimerIntervalTextBox" Text="1500" Margin="5,0,0,0" AutomationProperties.AutomationId="DynamicVisibilityTimerIntervalTextBox"/>
<TextBlock Text="Change Count:" Margin="5,0,0,0" VerticalAlignment="Center"/>
<TextBox x:Name="DynamicVisibilityChangeCountTextBox" Text="4" Margin="5,0,0,0" AutomationProperties.AutomationId="DynamicVisibilityChangeCountTextBox"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="10,0,10,2">
<CheckBox x:Name="UseOverflowContentRootDynamicWidthCheckBox" Content="Use OverflowContentRoot with Dynamic Width?" AutomationProperties.AutomationId="UseOverflowContentRootDynamicWidthCheckBox" />
<CheckBox x:Name="OverflowContentRootDynamicWidthChangedCheckBox" Content="Width Changed?" AutomationProperties.AutomationId="OverflowContentRootDynamicWidthChangedCheckBox" Margin="5,0,0,0" />
<TextBlock Text="Timer Interval (ms):" Margin="5,0,0,0" VerticalAlignment="Center"/>
<TextBox x:Name="DynamicWidthTimerIntervalTextBox" Text="1500" Margin="5,0,0,0" AutomationProperties.AutomationId="DynamicWidthTimerIntervalTextBox"/>
<TextBlock Text="Change Count:" Margin="5,0,0,0" VerticalAlignment="Center"/>
<TextBox x:Name="DynamicWidthChangeCountTextBox" Text="4" Margin="5,0,0,0" AutomationProperties.AutomationId="DynamicWidthChangeCountTextBox"/>
</StackPanel>
<CheckBox x:Name="ClearSecondaryCommandsCheckBox" Content="Clear Secondary Commands Asynchronously?" AutomationProperties.AutomationId="ClearSecondaryCommandsCheckBox" Margin="10,0,10,2" />
</StackPanel>
</ScrollViewer>
Expand Down
Loading

0 comments on commit 573e4a2

Please sign in to comment.