Merge pull request #4129 from Vijay-Nirmal/SmoothScrollMadeAsync

Changed SmoothScrollIntoView method to be truly asynchronous
This commit is contained in:
Michael Hawker MSFT (XAML Llama) 2021-08-02 15:22:52 -07:00 коммит произвёл GitHub
Родитель e4e06cbea6 b6749fc1b0
Коммит 51cbc9a109
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
3 изменённых файлов: 100 добавлений и 28 удалений

Просмотреть файл

@ -35,14 +35,16 @@
</Grid>
<StackPanel Grid.Column="1" Margin="5,10,10,0" Width="200">
<TextBlock Text="Smooth Scroll Settings" FontSize="{StaticResource TextStyleLargeFontSize}" Margin="0,0,0,10"/>
<TextBlock Text="Smooth Scroll Settings" FontSize="{StaticResource TextStyleLargeFontSize}"/>
<TextBox x:Name="IndexInput"
Header="Index"
InputScope="Number"
Text="100" />
Text="100"
Margin="0,10,0,0" />
<ComboBox x:Name="ItemPlacementInput"
Header="Item Placement"
SelectedIndex="0">
SelectedIndex="0"
Margin="0,10,0,0" >
<x:String>Default</x:String>
<x:String>Left</x:String>
<x:String>Top</x:String>
@ -52,18 +54,25 @@
</ComboBox>
<CheckBox x:Name="DisableAnimationInput"
Content="Disable Animation"
IsChecked="False" />
IsChecked="False"
Margin="0,10,0,0" />
<CheckBox x:Name="ScrollIfVisibileInput"
Content="Scroll If Visible"
IsChecked="True" />
<TextBox x:Name="AdditionalHorizontalOffsetInput"
Header="Horizontal Offset"
InputScope="Number"
Text="0" />
Text="0"
Margin="0,10,0,0" />
<TextBox x:Name="AdditionalVerticalOffsetInput"
Header="Vertical Offset"
InputScope="Number"
Text="0" />
Text="0"
Margin="0,10,0,0" />
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
<Ellipse x:Name="ScrollIndicator" Fill="Red" Width="15" Height="15"/>
<TextBlock x:Name="ScrollIndicatorTest" Text="Not Scrolling" Margin="10,0,0,0"/>
</StackPanel>
</StackPanel>
</Grid>
</Page>
</Page>

Просмотреть файл

@ -6,9 +6,11 @@ using System;
using System.Collections.ObjectModel;
using System.Windows.Input;
using Microsoft.Toolkit.Uwp.UI;
using Windows.UI;
using Windows.UI.Popups;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages
{
@ -37,7 +39,7 @@ namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages
private void Load()
{
SampleController.Current.RegisterNewCommand("Start Smooth Scroll", (sender, args) =>
SampleController.Current.RegisterNewCommand("Start Smooth Scroll", async (sender, args) =>
{
var index = int.TryParse(IndexInput.Text, out var i) ? i : 0;
var itemPlacement = ItemPlacementInput.SelectedItem switch
@ -55,7 +57,9 @@ namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages
var scrollIfVisibile = ScrollIfVisibileInput.IsChecked ?? true;
var additionalHorizontalOffset = int.TryParse(AdditionalHorizontalOffsetInput.Text, out var ho) ? ho : 0;
var additionalVerticalOffset = int.TryParse(AdditionalVerticalOffsetInput.Text, out var vo) ? vo : 0;
sampleListView.SmoothScrollIntoViewWithIndexAsync(index, itemPlacement, disableAnimation, scrollIfVisibile, additionalHorizontalOffset, additionalVerticalOffset);
UpdateScrollIndicator(true);
await sampleListView.SmoothScrollIntoViewWithIndexAsync(index, itemPlacement, disableAnimation, scrollIfVisibile, additionalHorizontalOffset, additionalVerticalOffset);
UpdateScrollIndicator(false);
});
if (sampleListView != null)
@ -64,6 +68,20 @@ namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages
}
}
private void UpdateScrollIndicator(bool isScrolling)
{
if (isScrolling)
{
ScrollIndicatorTest.Text = "Scrolling";
ScrollIndicator.Fill = new SolidColorBrush(Colors.Green);
}
else
{
ScrollIndicator.Fill = new SolidColorBrush(Colors.Red);
ScrollIndicatorTest.Text = "Not Scolling";
}
}
private ObservableCollection<string> GetOddEvenSource(int count)
{
var oddEvenSource = new ObservableCollection<string>();
@ -103,4 +121,4 @@ namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages
await new MessageDialog($"You clicked {item} via the 'ListViewExtensions.Command' binding", "Item Clicked").ShowAsync();
}
}
}
}

Просмотреть файл

@ -26,7 +26,7 @@ namespace Microsoft.Toolkit.Uwp.UI
/// <param name="scrollIfVisible">Set false to disable scrolling when the corresponding item is in view</param>
/// <param name="additionalHorizontalOffset">Adds additional horizontal offset</param>
/// <param name="additionalVerticalOffset">Adds additional vertical offset</param>
/// <returns>Note: Even though this return <see cref="Task"/>, it will not wait until the scrolling completes</returns>
/// <returns>Returns <see cref="Task"/> that completes after scrolling</returns>
public static async Task SmoothScrollIntoViewWithIndexAsync(this ListViewBase listViewBase, int index, ScrollItemPlacement itemPlacement = ScrollItemPlacement.Default, bool disableAnimation = false, bool scrollIfVisible = true, int additionalHorizontalOffset = 0, int additionalVerticalOffset = 0)
{
if (index > (listViewBase.Items.Count - 1))
@ -58,7 +58,7 @@ namespace Microsoft.Toolkit.Uwp.UI
var tcs = new TaskCompletionSource<object>();
void ViewChanged(object obj, ScrollViewerViewChangedEventArgs args) => tcs.TrySetResult(result: null);
void ViewChanged(object _, ScrollViewerViewChangedEventArgs __) => tcs.TrySetResult(result: default);
try
{
@ -80,20 +80,7 @@ namespace Microsoft.Toolkit.Uwp.UI
// Scrolling back to previous position
if (isVirtualizing)
{
var tcs = new TaskCompletionSource<object>();
void ViewChanged(object obj, ScrollViewerViewChangedEventArgs args) => tcs.TrySetResult(result: null);
try
{
scrollViewer.ViewChanged += ViewChanged;
scrollViewer.ChangeView(previousXOffset, previousYOffset, zoomFactor: null, disableAnimation: true);
await tcs.Task;
}
finally
{
scrollViewer.ViewChanged -= ViewChanged;
}
await scrollViewer.ChangeViewAsync(previousXOffset, previousYOffset, zoomFactor: null, disableAnimation: true);
}
var listViewBaseWidth = listViewBase.ActualWidth;
@ -185,7 +172,7 @@ namespace Microsoft.Toolkit.Uwp.UI
}
}
scrollViewer.ChangeView(finalXPosition, finalYPosition, zoomFactor: null, disableAnimation);
await scrollViewer.ChangeViewAsync(finalXPosition, finalYPosition, zoomFactor: null, disableAnimation);
}
/// <summary>
@ -198,10 +185,68 @@ namespace Microsoft.Toolkit.Uwp.UI
/// <param name="scrollIfVisibile">Set true to disable scrolling when the corresponding item is in view</param>
/// <param name="additionalHorizontalOffset">Adds additional horizontal offset</param>
/// <param name="additionalVerticalOffset">Adds additional vertical offset</param>
/// <returns>Note: Even though this return <see cref="Task"/>, it will not wait until the scrolling completes</returns>
/// <returns>Returns <see cref="Task"/> that completes after scrolling</returns>
public static async Task SmoothScrollIntoViewWithItemAsync(this ListViewBase listViewBase, object item, ScrollItemPlacement itemPlacement = ScrollItemPlacement.Default, bool disableAnimation = false, bool scrollIfVisibile = true, int additionalHorizontalOffset = 0, int additionalVerticalOffset = 0)
{
await SmoothScrollIntoViewWithIndexAsync(listViewBase, listViewBase.Items.IndexOf(item), itemPlacement, disableAnimation, scrollIfVisibile, additionalHorizontalOffset, additionalVerticalOffset);
}
/// <summary>
/// Changes the view of <see cref="ScrollViewer"/> asynchronous.
/// </summary>
/// <param name="scrollViewer">The scroll viewer.</param>
/// <param name="horizontalOffset">The horizontal offset.</param>
/// <param name="verticalOffset">The vertical offset.</param>
/// <param name="zoomFactor">The zoom factor.</param>
/// <param name="disableAnimation">if set to <c>true</c> disable animation.</param>
private static async Task ChangeViewAsync(this ScrollViewer scrollViewer, double? horizontalOffset, double? verticalOffset, float? zoomFactor, bool disableAnimation)
{
if (horizontalOffset > scrollViewer.ScrollableWidth)
{
horizontalOffset = scrollViewer.ScrollableWidth;
}
else if (horizontalOffset < 0)
{
horizontalOffset = 0;
}
if (verticalOffset > scrollViewer.ScrollableHeight)
{
verticalOffset = scrollViewer.ScrollableHeight;
}
else if (verticalOffset < 0)
{
verticalOffset = 0;
}
// MUST check this and return immediately, otherwise this async task will never complete because ViewChanged event won't get triggered
if (horizontalOffset == scrollViewer.HorizontalOffset && verticalOffset == scrollViewer.VerticalOffset)
{
return;
}
var tcs = new TaskCompletionSource<object>();
void ViewChanged(object _, ScrollViewerViewChangedEventArgs e)
{
if (e.IsIntermediate)
{
return;
}
tcs.TrySetResult(result: default);
}
try
{
scrollViewer.ViewChanged += ViewChanged;
scrollViewer.ChangeView(horizontalOffset, verticalOffset, zoomFactor, disableAnimation);
await tcs.Task;
}
finally
{
scrollViewer.ViewChanged -= ViewChanged;
}
}
}
}