Skip to content

CommandBarFlyoutCommandBar fix - respond to size changes #6868

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

Merged
merged 1 commit into from
Mar 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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