Skip to content

Commit 68abde4

Browse files
authored
Disable TabView scroll buttons based on scroll position (#2162)
* Disable TabView scroll buttons based on scroll position Disable TabView scroll buttons based on scroll position * Store the return value of scrollViewer.ViewChanged in a revoker Store the return value of scrollViewer.ViewChanged in a revoker * Setup UI for testing scroll viewer's increase/decrease button Setup UI for testing scroll viewer's increase/decrease button * Save decrease/increase button ref for future use and address few comments Save decrease/increase button ref for future use and address few comments * Added UI tests Added UI tests * Adding a sleep after each scrolling to make sure view state get updated Adding a sleep after each scrolling to make sure view state get updated * Use Wait.ForMilliseconds instead of Thread.Sleep Use Wait.ForMilliseconds instead of Thread.Sleep * Use Wait.ForIdle() instead Use Wait.ForIdle() instead * Disable scrolling animation Disable scrolling animation * Remove unused namespace Remove unused namespace * Resolve comments Resolve comments
1 parent 7d42841 commit 68abde4

File tree

5 files changed

+127
-1
lines changed

5 files changed

+127
-1
lines changed

dev/TabView/InteractionTests/TabViewTests.cs

+32
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,24 @@ public void TabSizeAndScrollButtonsTest()
140140
// With largerTab now rendering wider, the scroll buttons should appear:
141141
Verify.IsTrue(AreScrollButtonsVisible(), "Scroll buttons should appear");
142142

143+
// Scroll all the way to the left and verify decrease/increase button visual state
144+
FindElement.ByName<Button>("ScrollTabViewToTheLeft").InvokeAndWait();
145+
Wait.ForIdle();
146+
Verify.IsFalse(IsScrollDecreaseButtonEnabled(), "Scroll decrease button should be disabled");
147+
Verify.IsTrue(IsScrollIncreaseButtonEnabled(), "Scroll increase button should be enabled");
148+
149+
// Scroll to the middle position and verify decrease/increase button visual state
150+
FindElement.ByName<Button>("ScrollTabViewToTheMiddle").InvokeAndWait();
151+
Wait.ForIdle();
152+
Verify.IsTrue(IsScrollDecreaseButtonEnabled(), "Scroll decrease button should be enabled");
153+
Verify.IsTrue(IsScrollIncreaseButtonEnabled(), "Scroll increase button should be enabled");
154+
155+
// Scroll all the way to the right and verify decrease/increase button visual state
156+
FindElement.ByName<Button>("ScrollTabViewToTheRight").InvokeAndWait();
157+
Wait.ForIdle();
158+
Verify.IsTrue(IsScrollDecreaseButtonEnabled(), "Scroll decrease button should be enabled");
159+
Verify.IsFalse(IsScrollIncreaseButtonEnabled(), "Scroll increase button should be disabled");
160+
143161
// Close a tab to make room. The scroll buttons should disappear:
144162
Log.Comment("Closing a tab:");
145163
Button closeButton = FindCloseButton(FindElement.ByName("LongHeaderTab"));
@@ -186,6 +204,20 @@ private bool AreScrollButtonsVisible()
186204
}
187205
}
188206

207+
private bool IsScrollIncreaseButtonEnabled()
208+
{
209+
FindElement.ByName<Button>("GetScrollIncreaseButtonEnabled").InvokeAndWait();
210+
var scrollIncreaseButtonEnabled = FindElement.ByName<TextBlock>("ScrollIncreaseButtonEnabled").DocumentText;
211+
return scrollIncreaseButtonEnabled == "True";
212+
}
213+
214+
private bool IsScrollDecreaseButtonEnabled()
215+
{
216+
FindElement.ByName<Button>("GetScrollDecreaseButtonEnabled").InvokeAndWait();
217+
var scrollDecreaseButtonEnabled = FindElement.ByName<TextBlock>("ScrollDecreaseButtonEnabled").DocumentText;
218+
return scrollDecreaseButtonEnabled == "True";
219+
}
220+
189221
[TestMethod]
190222
public void CloseSelectionTest()
191223
{

dev/TabView/TabView.cpp

+46-1
Original file line numberDiff line numberDiff line change
@@ -346,18 +346,57 @@ void TabView::OnScrollViewerLoaded(const winrt::IInspectable&, const winrt::Rout
346346
if (auto&& scrollViewer = m_scrollViewer.get())
347347
{
348348
auto decreaseButton = SharedHelpers::FindInVisualTreeByName(scrollViewer, L"ScrollDecreaseButton").as<winrt::RepeatButton>();
349+
m_scrollDecreaseButton.set(decreaseButton);
349350
m_scrollDecreaseClickRevoker = decreaseButton.Click(winrt::auto_revoke, { this, &TabView::OnScrollDecreaseClick });
350351

351352
auto increaseButton = SharedHelpers::FindInVisualTreeByName(scrollViewer, L"ScrollIncreaseButton").as<winrt::RepeatButton>();
353+
m_scrollIncreaseButton.set(increaseButton);
352354
m_scrollIncreaseClickRevoker = increaseButton.Click(winrt::auto_revoke, { this, &TabView::OnScrollIncreaseClick });
355+
356+
m_scrollViewerViewChangedRevoker = scrollViewer.ViewChanged(winrt::auto_revoke, { this, &TabView::OnScrollViewerViewChanged });
353357
}
354358

355359
UpdateTabWidths();
356360
}
357361

362+
void TabView::OnScrollViewerViewChanged(winrt::IInspectable const& sender, winrt::ScrollViewerViewChangedEventArgs const& args)
363+
{
364+
UpdateScrollViewerDecreaseAndIncreaseButtonsViewState();
365+
}
366+
367+
void TabView::UpdateScrollViewerDecreaseAndIncreaseButtonsViewState()
368+
{
369+
if (auto&& scrollViewer = m_scrollViewer.get())
370+
{
371+
auto&& decreaseButton = m_scrollDecreaseButton.get();
372+
auto&& increaseButton = m_scrollIncreaseButton.get();
373+
374+
constexpr auto minThreshold = 0.1;
375+
auto horizontalOffset = scrollViewer.HorizontalOffset();
376+
auto scrollableWidth = scrollViewer.ScrollableWidth();
377+
378+
if (abs(horizontalOffset - scrollableWidth) < minThreshold)
379+
{
380+
decreaseButton.IsEnabled(true);
381+
increaseButton.IsEnabled(false);
382+
}
383+
else if (abs(horizontalOffset) < minThreshold)
384+
{
385+
decreaseButton.IsEnabled(false);
386+
increaseButton.IsEnabled(true);
387+
}
388+
else
389+
{
390+
decreaseButton.IsEnabled(true);
391+
increaseButton.IsEnabled(true);
392+
}
393+
}
394+
}
395+
358396
void TabView::OnItemsPresenterSizeChanged(const winrt::IInspectable& sender, const winrt::SizeChangedEventArgs& args)
359397
{
360398
UpdateTabWidths();
399+
UpdateScrollViewerDecreaseAndIncreaseButtonsViewState();
361400
}
362401

363402
void TabView::OnItemsChanged(winrt::IInspectable const& item)
@@ -636,6 +675,7 @@ void TabView::UpdateTabWidths()
636675
if (auto listview = m_listView.get())
637676
{
638677
winrt::FxScrollViewer::SetHorizontalScrollBarVisibility(listview, winrt::Windows::UI::Xaml::Controls::ScrollBarVisibility::Visible);
678+
UpdateScrollViewerDecreaseAndIncreaseButtonsViewState();
639679
}
640680
}
641681
else
@@ -659,9 +699,14 @@ void TabView::UpdateTabWidths()
659699
// Calculate if the scroll buttons should be visible.
660700
if (auto itemsPresenter = m_itemsPresenter.get())
661701
{
662-
winrt::FxScrollViewer::SetHorizontalScrollBarVisibility(listview, itemsPresenter.ActualWidth() > availableWidth
702+
auto visible = itemsPresenter.ActualWidth() > availableWidth;
703+
winrt::FxScrollViewer::SetHorizontalScrollBarVisibility(listview, visible
663704
? winrt::Windows::UI::Xaml::Controls::ScrollBarVisibility::Visible
664705
: winrt::Windows::UI::Xaml::Controls::ScrollBarVisibility::Hidden);
706+
if (visible)
707+
{
708+
UpdateScrollViewerDecreaseAndIncreaseButtonsViewState();
709+
}
665710
}
666711
}
667712
}

dev/TabView/TabView.h

+6
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ class TabView :
123123
void OnAddButtonClick(const winrt::IInspectable& sender, const winrt::RoutedEventArgs& args);
124124
void OnScrollDecreaseClick(const winrt::IInspectable& sender, const winrt::RoutedEventArgs& args);
125125
void OnScrollIncreaseClick(const winrt::IInspectable& sender, const winrt::RoutedEventArgs& args);
126+
void OnScrollViewerViewChanged(winrt::IInspectable const& sender, winrt::ScrollViewerViewChangedEventArgs const& args);
126127
void OnItemsPresenterSizeChanged(const winrt::IInspectable& sender, const winrt::SizeChangedEventArgs& args);
127128

128129
void OnListViewLoaded(const winrt::IInspectable& sender, const winrt::RoutedEventArgs& args);
@@ -145,6 +146,8 @@ class TabView :
145146

146147
void UpdateTabWidths();
147148

149+
void UpdateScrollViewerDecreaseAndIncreaseButtonsViewState();
150+
148151
void OnListViewGettingFocus(const winrt::IInspectable& sender, const winrt::GettingFocusEventArgs& args);
149152

150153
int GetItemCount();
@@ -161,6 +164,8 @@ class TabView :
161164
tracker_ref<winrt::ContentPresenter> m_rightContentPresenter{ this };
162165
tracker_ref<winrt::Grid> m_tabContainerGrid{ this };
163166
tracker_ref<winrt::FxScrollViewer> m_scrollViewer{ this };
167+
tracker_ref<winrt::RepeatButton> m_scrollDecreaseButton{ this };
168+
tracker_ref<winrt::RepeatButton> m_scrollIncreaseButton{ this };
164169
tracker_ref<winrt::Button> m_addButton{ this };
165170
tracker_ref<winrt::ItemsPresenter> m_itemsPresenter{ this };
166171

@@ -176,6 +181,7 @@ class TabView :
176181
winrt::UIElement::Drop_revoker m_listViewDropRevoker{};
177182

178183
winrt::FxScrollViewer::Loaded_revoker m_scrollViewerLoadedRevoker{};
184+
winrt::FxScrollViewer::ViewChanged_revoker m_scrollViewerViewChangedRevoker{};
179185

180186
winrt::Button::Click_revoker m_addButtonClickRevoker{};
181187

dev/TabView/TestUI/TabViewPage.xaml

+13
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@
4848
<Button x:Name="ChangeShopTextButton" AutomationProperties.Name="ChangeShopTextButton" Content="Change Shop text" Margin="0,0,0,8" Click="ChangeShopTextButton_Click"/>
4949
<Button x:Name="CustomTooltipButton" AutomationProperties.Name="CustomTooltipButton" Content="Custom Tooltip" Margin="0,0,0,8" Click="CustomTooltipButton_Click"/>
5050
<Button x:Name="SetTabViewWidth" AutomationProperties.Name="SetTabViewWidth" Content="Set Width" Margin="0,0,0,8" Click="SetTabViewWidth_Click" />
51+
<Button x:Name="ScrollTabViewToTheLeft" AutomationProperties.Name="ScrollTabViewToTheLeft" Content="Scroll TabView To the Left" Margin="0,0,0,8" Click="TabViewScrollToTheLeftButton_Click" />
52+
<Button x:Name="ScrollTabViewToTheMiddle" AutomationProperties.Name="ScrollTabViewToTheMiddle" Content="Scroll TabView To the Middle" Margin="0,0,0,8" Click="TabViewScrollToTheMiddleButton_Click" />
53+
<Button x:Name="ScrollTabViewToTheRight" AutomationProperties.Name="ScrollTabViewToTheRight" Content="Scroll TabView To the Right" Margin="0,0,0,8" Click="TabViewScrollToTheRightButton_Click" />
5154

5255
<Button x:Name="ShortLongTextButton" AutomationProperties.Name="ShortLongTextButton" Content="Short/Long Text" Margin="0,0,0,8" Click="ShortLongTextButton_Click" />
5356

@@ -60,7 +63,17 @@
6063
<Button x:Name="GetScrollButtonsVisible" AutomationProperties.Name="GetScrollButtonsVisible" Content="Get" Margin="4,0,0,0" Click="GetScrollButtonsVisible_Click" />
6164
</StackPanel>
6265

66+
<StackPanel Orientation="Horizontal" Margin="0,0,0,8">
67+
<TextBlock Text="DecreaseButton enabled:" VerticalAlignment="Center" Margin="0,0,4,0"/>
68+
<TextBlock x:Name="ScrollDecreaseButtonEnabled" AutomationProperties.Name="ScrollDecreaseButtonEnabled" Text="False" VerticalAlignment="Center"/>
69+
<Button x:Name="GetScrollDecreaseButtonEnabled" AutomationProperties.Name="GetScrollDecreaseButtonEnabled" Content="Get" Margin="4,0,0,0" Click="GetScrollDecreaseButtonEnabled_Click" />
70+
</StackPanel>
6371

72+
<StackPanel Orientation="Horizontal" Margin="0,0,0,8">
73+
<TextBlock Text="IncreaseButton enabled:" VerticalAlignment="Center" Margin="0,0,4,0"/>
74+
<TextBlock x:Name="ScrollIncreaseButtonEnabled" AutomationProperties.Name="ScrollIncreaseButtonEnabled" Text="False" VerticalAlignment="Center"/>
75+
<Button x:Name="GetScrollIncreaseButtonEnabled" AutomationProperties.Name="GetScrollIncreaseButtonEnabled" Content="Get" Margin="4,0,0,0" Click="GetScrollIncreaseButtonEnabled_Click" />
76+
</StackPanel>
6477

6578
<StackPanel Orientation="Horizontal" Margin="0,0,0,8">
6679
<TextBlock>Selected Index:</TextBlock>

dev/TabView/TestUI/TabViewPage.xaml.cs

+30
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,36 @@ public void GetScrollButtonsVisible_Click(object sender, RoutedEventArgs e)
359359
}
360360
}
361361

362+
public void TabViewScrollToTheLeftButton_Click(object sender, RoutedEventArgs e)
363+
{
364+
var scrollViewer = VisualTreeUtils.FindVisualChildByName(Tabs, "ScrollViewer") as ScrollViewer;
365+
scrollViewer.ChangeView(0, null, null, true);
366+
}
367+
368+
public void TabViewScrollToTheMiddleButton_Click(object sender, RoutedEventArgs e)
369+
{
370+
var scrollViewer = VisualTreeUtils.FindVisualChildByName(Tabs, "ScrollViewer") as ScrollViewer;
371+
scrollViewer.ChangeView(scrollViewer.ScrollableWidth / 2.0f, null, null, true);
372+
}
373+
374+
public void TabViewScrollToTheRightButton_Click(object sender, RoutedEventArgs e)
375+
{
376+
var scrollViewer = VisualTreeUtils.FindVisualChildByName(Tabs, "ScrollViewer") as ScrollViewer;
377+
scrollViewer.ChangeView(double.MaxValue, null, null, true);
378+
}
379+
380+
public void GetScrollDecreaseButtonEnabled_Click(object sender, RoutedEventArgs e)
381+
{
382+
var scrollDecreaseButton = VisualTreeUtils.FindVisualChildByName(Tabs, "ScrollDecreaseButton") as RepeatButton;
383+
ScrollDecreaseButtonEnabled.Text = scrollDecreaseButton.IsEnabled ? "True" : "False";
384+
}
385+
386+
public void GetScrollIncreaseButtonEnabled_Click(object sender, RoutedEventArgs e)
387+
{
388+
var scrollIncreaseButton = VisualTreeUtils.FindVisualChildByName(Tabs, "ScrollIncreaseButton") as RepeatButton;
389+
ScrollIncreaseButtonEnabled.Text = scrollIncreaseButton.IsEnabled ? "True" : "False";
390+
}
391+
362392
private void TabViewSizingPageButton_Click(object sender, RoutedEventArgs e)
363393
{
364394
this.Frame.Navigate(typeof(TabViewSizingPage));

0 commit comments

Comments
 (0)