Skip to content
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

[TabView] Fix bug where removing tabs from tabcollection would not resize tabs #6160

Merged
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
89 changes: 89 additions & 0 deletions dev/TabView/InteractionTests/TabViewTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,95 @@ double GetActualTabViewWidth()
}
}

[TestMethod]
public void VerifySizingBehaviorModifyingCollectionRemovingLastItem()
{
int pixelTolerance = 5;

using (var setup = new TestSetupHelper(new[] { "TabView Tests", "TabViewTabClosingBehaviorButton" }))
{

Log.Comment("Verifying sizing behavior when removing the last tab from tab collection");
CloseTabAndVerifyWidth("Tab 5", 500, 100);

CloseTabAndVerifyWidth("Tab 4", 500, 100);

CloseTabAndVerifyWidth("Tab 3", 500, 140);

CloseTabAndVerifyWidth("Tab 2", 500, 225);
}

void CloseTabAndVerifyWidth(string tabName, int expectedWidth, int expectedItemWidth)
{
Log.Comment("Closing tab:" + tabName);
new Button(FindElement.ByName("RemoveLastItemButton")).Click();
Wait.ForIdle();
new Button(FindElement.ByName("GetActualWidthButton")).Click();
Log.Comment("Verifying TabView width");
Verify.IsTrue(Math.Abs(GetActualTabViewWidth() - expectedWidth) < pixelTolerance);
var firstTabItemWidth = GetFirstTabItemWidth();
Verify.IsTrue(Math.Abs(firstTabItemWidth - expectedItemWidth) < pixelTolerance);
}

double GetActualTabViewWidth()
{
var tabviewWidth = new TextBlock(FindElement.ByName("TabViewWidth"));

return double.Parse(tabviewWidth.GetText());
}

double GetFirstTabItemWidth()
{
var tabviewWidth = new TextBlock(FindElement.ByName("TabViewHeaderWidth"));

return double.Parse(tabviewWidth.GetText().Split(".")[0]);
}
}

[TestMethod]
public void VerifySizingBehaviorModifyingCollectionRemovingSecondItem()
{
int pixelTolerance = 5;

using (var setup = new TestSetupHelper(new[] { "TabView Tests", "TabViewTabClosingBehaviorButton" }))
{

Log.Comment("Verifying sizing behavior when removing the second tab from tab collection");
CloseTabAndVerifyWidth("Tab 5", 500, 100);

CloseTabAndVerifyWidth("Tab 4", 500, 100);

CloseTabAndVerifyWidth("Tab 3", 500, 140);

CloseTabAndVerifyWidth("Tab 2", 500, 225);
}

void CloseTabAndVerifyWidth(string tabName, int expectedWidth, int expectedItemWidth)
{
Log.Comment("Closing tab:" + tabName);
new Button(FindElement.ByName("RemoveMiddleItemButton")).Click();
Wait.ForIdle();
new Button(FindElement.ByName("GetActualWidthButton")).Click();
Log.Comment("Verifying TabView width");
Verify.IsTrue(Math.Abs(GetActualTabViewWidth() - expectedWidth) < pixelTolerance);
Verify.IsTrue(Math.Abs(GetFirstTabItemWidth() - expectedItemWidth) < pixelTolerance);
}

double GetActualTabViewWidth()
{
var tabviewWidth = new TextBlock(FindElement.ByName("TabViewWidth"));

return double.Parse(tabviewWidth.GetText());
}

double GetFirstTabItemWidth()
{
var tabviewWidth = new TextBlock(FindElement.ByName("TabViewHeaderWidth"));

return double.Parse(tabviewWidth.GetText().Split(".")[0]);
}
}

[TestMethod]
public void VerifySizingBehaviorOnTabCloseComingFromCtrlF4()
{
Expand Down
13 changes: 9 additions & 4 deletions dev/TabView/TabView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ void TabView::OnApplyTemplate()
{
m_tabContainerGrid.set(containerGrid);
m_tabStripPointerExitedRevoker = containerGrid.PointerExited(winrt::auto_revoke, { this,&TabView::OnTabStripPointerExited });
m_tabStripPointerEnteredRevoker = containerGrid.PointerEntered(winrt::auto_revoke, { this,&TabView::OnTabStripPointerEntered });
}

if (!SharedHelpers::Is21H1OrHigher())
Expand Down Expand Up @@ -355,6 +356,7 @@ void TabView::UnhookEventsAndClearFields()
m_addButtonClickRevoker.revoke();
m_itemsPresenterSizeChangedRevoker.revoke();
m_tabStripPointerExitedRevoker.revoke();
m_tabStripPointerEnteredRevoker.revoke();
m_scrollViewerLoadedRevoker.revoke();
m_scrollViewerViewChangedRevoker.revoke();
m_scrollDecreaseClickRevoker.revoke();
Expand Down Expand Up @@ -508,6 +510,7 @@ void TabView::OnListViewLoaded(const winrt::IInspectable&, const winrt::RoutedEv

void TabView::OnTabStripPointerExited(const winrt::IInspectable& sender, const winrt::PointerRoutedEventArgs& args)
{
m_pointerInTabstrip = false;
if (m_updateTabWidthOnPointerLeave)
{
auto scopeGuard = gsl::finally([this]()
Expand All @@ -518,6 +521,11 @@ void TabView::OnTabStripPointerExited(const winrt::IInspectable& sender, const w
}
}

void TabView::OnTabStripPointerEntered(const winrt::IInspectable& sender, const winrt::PointerRoutedEventArgs& args)
{
m_pointerInTabstrip = true;
}

void TabView::OnScrollViewerLoaded(const winrt::IInspectable&, const winrt::RoutedEventArgs& args)
{
if (auto&& scrollViewer = m_scrollViewer.get())
Expand Down Expand Up @@ -678,12 +686,9 @@ void TabView::OnItemsChanged(winrt::IInspectable const& item)
}

}
// Last item removed, update sizes
// The index of the last element is "Size() - 1", but in TabItems, it is already removed.
if (TabWidthMode() == winrt::TabViewWidthMode::Equal)
{
m_updateTabWidthOnPointerLeave = true;
if (args.Index() == TabItems().Size())
if (!m_pointerInTabstrip || args.Index() == TabItems().Size())
{
UpdateTabWidths(true, false);
}
Expand Down
3 changes: 3 additions & 0 deletions dev/TabView/TabView.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ class TabView :

void OnListViewLoaded(const winrt::IInspectable& sender, const winrt::RoutedEventArgs& args);
void OnTabStripPointerExited(const winrt::IInspectable& sender, const winrt::PointerRoutedEventArgs& args);
void OnTabStripPointerEntered(const winrt::IInspectable& sender, const winrt::PointerRoutedEventArgs& args);
void OnListViewSelectionChanged(const winrt::IInspectable& sender, const winrt::SelectionChangedEventArgs& args);

void OnListViewDragItemsStarting(const winrt::IInspectable& sender, const winrt::DragItemsStartingEventArgs& args);
Expand Down Expand Up @@ -166,6 +167,7 @@ class TabView :
winrt::TabViewItem FindTabViewItemFromDragItem(const winrt::IInspectable& item);

bool m_updateTabWidthOnPointerLeave{ false };
bool m_pointerInTabstrip{ false };

tracker_ref<winrt::ColumnDefinition> m_leftContentColumn{ this };
tracker_ref<winrt::ColumnDefinition> m_tabColumn{ this };
Expand All @@ -186,6 +188,7 @@ class TabView :

winrt::ListView::Loaded_revoker m_listViewLoadedRevoker{};
winrt::ListView::PointerExited_revoker m_tabStripPointerExitedRevoker{};
winrt::ListView::PointerEntered_revoker m_tabStripPointerEnteredRevoker{};
winrt::Selector::SelectionChanged_revoker m_listViewSelectionChangedRevoker{};
winrt::UIElement::GettingFocus_revoker m_listViewGettingFocusRevoker{};

Expand Down
6 changes: 4 additions & 2 deletions dev/TabView/TestUI/TabViewTabClosingBehaviorPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@
TabCloseRequested="TabViewTabCloseRequested"
AddTabButtonClick="AddButtonClick">

<muxc:TabViewItem Header="Tab 0" AutomationProperties.Name="Tab 0"/>
<muxc:TabViewItem Header="Tab 0" x:Name="Tab0" AutomationProperties.Name="Tab 0"/>
<muxc:TabViewItem Header="Tab 1" AutomationProperties.Name="Tab 1"/>
<muxc:TabViewItem Header="Tab 2" AutomationProperties.Name="Tab 2"/>
<muxc:TabViewItem Header="Tab 3" x:Name="Tab3" AutomationProperties.Name="Tab 3"/>
<muxc:TabViewItem Header="Tab 3" AutomationProperties.Name="Tab 3"/>
<muxc:TabViewItem Header="Tab 4" AutomationProperties.Name="Tab 4"/>
<muxc:TabViewItem Header="Tab 5" AutomationProperties.Name="Tab 5"/>
</muxc:TabView>
Expand All @@ -43,6 +43,8 @@
<Button AutomationProperties.Name="IncreaseScrollButton"
Click="IncreaseScrollButton_Click"
Content="Increase scroll" />
<Button AutomationProperties.Name="RemoveMiddleItemButton" Click="RemoveMiddleItem_Click" Content="Remove Middle item"/>
<Button AutomationProperties.Name="RemoveLastItemButton" Click="RemoveLastItem_Click" Content="Remove last item"/>
</StackPanel>
</StackPanel>
</Grid>
Expand Down
21 changes: 19 additions & 2 deletions dev/TabView/TestUI/TabViewTabClosingBehaviorPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ private void TabViewTabCloseRequested(object sender, Microsoft.UI.Xaml.Controls.
Tabs.TabItems.Remove(e.Tab);

TabViewWidth.Text = Tabs.ActualWidth.ToString();
TabViewHeaderWidth.Text = Tab3.Width.ToString();
TabViewHeaderWidth.Text = Tab0.Width.ToString();

var scrollButtonStateValue = "";

Expand All @@ -63,13 +63,21 @@ private void TabViewTabCloseRequested(object sender, Microsoft.UI.Xaml.Controls.
ScrollButtonStatus.Text = scrollButtonStateValue;
}

public void GetFirstItemWidthButton_Click(object sender, RoutedEventArgs e)
{
// This is the smallest width that fits our content without any scrolling.
TabViewWidth.Text = Tabs.ActualWidth.ToString();

// Header width
TabViewHeaderWidth.Text = Tab0.Width.ToString();
}
public void GetActualWidthsButton_Click(object sender, RoutedEventArgs e)
{
// This is the smallest width that fits our content without any scrolling.
TabViewWidth.Text = Tabs.ActualWidth.ToString();

// Header width
TabViewHeaderWidth.Text = Tab3.Width.ToString();
TabViewHeaderWidth.Text = Tab0.Width.ToString();
}

public void IncreaseScrollButton_Click(object sender, RoutedEventArgs e)
Expand All @@ -78,5 +86,14 @@ public void IncreaseScrollButton_Click(object sender, RoutedEventArgs e)
sv.ChangeView(10000, null, null, disableAnimation: true);
}

private void RemoveMiddleItem_Click(object sender, RoutedEventArgs e)
{
Tabs.TabItems.RemoveAt(1);
}

private void RemoveLastItem_Click(object sender, RoutedEventArgs e)
{
Tabs.TabItems.RemoveAt(Tabs.TabItems.Count - 1);
}
}
}
4 changes: 2 additions & 2 deletions test/testinfra/MUXTestInfra/Infra/Application.cs
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ private UIObject LaunchApp()
catch (Exception ex)
{
Log.Comment("Failed to launch app. Exception: " + ex.ToString());

if (retries < MaxLaunchRetries)
{
Log.Comment("UAPApp.Launch might not have waited long enough, trying again {0}", retries);
Expand Down Expand Up @@ -354,7 +354,7 @@ private void EnsureApplicationProcessHasExited(int appWindowsProccessId)
// 3. Use the Process obj we found when this Application object was initialized.
// This is just a sanity check. Under normal circumstances, there should only be
// one app process.

var appProcesses = Process.GetProcessesByName(_appProcessName).ToList();

if (appWindowsProccessId != -1)
Expand Down