diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ListViewExtensions/ListViewExtensionsPage.xaml b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ListViewExtensions/ListViewExtensionsPage.xaml index 625285f44be..bb50bbcf3e6 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ListViewExtensions/ListViewExtensionsPage.xaml +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ListViewExtensions/ListViewExtensionsPage.xaml @@ -35,14 +35,16 @@ - + + Text="100" + Margin="0,10,0,0" /> + SelectedIndex="0" + Margin="0,10,0,0" > Default Left Top @@ -52,18 +54,25 @@ + IsChecked="False" + Margin="0,10,0,0" /> + Text="0" + Margin="0,10,0,0" /> + Text="0" + Margin="0,10,0,0" /> + + + + - \ No newline at end of file + diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ListViewExtensions/ListViewExtensionsPage.xaml.cs b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ListViewExtensions/ListViewExtensionsPage.xaml.cs index b79849ef196..cd547d2bd77 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ListViewExtensions/ListViewExtensionsPage.xaml.cs +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ListViewExtensions/ListViewExtensionsPage.xaml.cs @@ -6,9 +6,11 @@ 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 @@ public void OnXamlRendered(FrameworkElement control) 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 @@ private void Load() 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 @@ private void Load() } } + 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 GetOddEvenSource(int count) { var oddEvenSource = new ObservableCollection(); @@ -103,4 +121,4 @@ private static async void OnExecuteSampleCommand(string item) await new MessageDialog($"You clicked {item} via the 'ListViewExtensions.Command' binding", "Item Clicked").ShowAsync(); } } -} \ No newline at end of file +} diff --git a/Microsoft.Toolkit.Uwp.UI/Extensions/ListViewBase/ListViewExtensions.SmoothScrollIntoView.cs b/Microsoft.Toolkit.Uwp.UI/Extensions/ListViewBase/ListViewExtensions.SmoothScrollIntoView.cs index 419471d959b..c32bf5c4d88 100644 --- a/Microsoft.Toolkit.Uwp.UI/Extensions/ListViewBase/ListViewExtensions.SmoothScrollIntoView.cs +++ b/Microsoft.Toolkit.Uwp.UI/Extensions/ListViewBase/ListViewExtensions.SmoothScrollIntoView.cs @@ -26,7 +26,7 @@ public static partial class ListViewExtensions /// Set false to disable scrolling when the corresponding item is in view /// Adds additional horizontal offset /// Adds additional vertical offset - /// Note: Even though this return , it will not wait until the scrolling completes + /// Returns that completes after scrolling 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 @@ public static async Task SmoothScrollIntoViewWithIndexAsync(this ListViewBase li var tcs = new TaskCompletionSource(); - void ViewChanged(object obj, ScrollViewerViewChangedEventArgs args) => tcs.TrySetResult(result: null); + void ViewChanged(object _, ScrollViewerViewChangedEventArgs __) => tcs.TrySetResult(result: default); try { @@ -80,20 +80,7 @@ public static async Task SmoothScrollIntoViewWithIndexAsync(this ListViewBase li // Scrolling back to previous position if (isVirtualizing) { - var tcs = new TaskCompletionSource(); - - 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 @@ public static async Task SmoothScrollIntoViewWithIndexAsync(this ListViewBase li } } - scrollViewer.ChangeView(finalXPosition, finalYPosition, zoomFactor: null, disableAnimation); + await scrollViewer.ChangeViewAsync(finalXPosition, finalYPosition, zoomFactor: null, disableAnimation); } /// @@ -198,10 +185,68 @@ public static async Task SmoothScrollIntoViewWithIndexAsync(this ListViewBase li /// Set true to disable scrolling when the corresponding item is in view /// Adds additional horizontal offset /// Adds additional vertical offset - /// Note: Even though this return , it will not wait until the scrolling completes + /// Returns that completes after scrolling 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); } + + /// + /// Changes the view of asynchronous. + /// + /// The scroll viewer. + /// The horizontal offset. + /// The vertical offset. + /// The zoom factor. + /// if set to true disable animation. + 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(); + + 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; + } + } } }