@@ -26,7 +26,7 @@ public static partial class ListViewExtensions
26
26
/// <param name="scrollIfVisible">Set false to disable scrolling when the corresponding item is in view</param>
27
27
/// <param name="additionalHorizontalOffset">Adds additional horizontal offset</param>
28
28
/// <param name="additionalVerticalOffset">Adds additional vertical offset</param>
29
- /// <returns>Note: Even though this return <see cref="Task"/>, it will not wait until the scrolling completes </returns>
29
+ /// <returns>Returns <see cref="Task"/> that completes after scrolling</returns>
30
30
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 )
31
31
{
32
32
if ( index > ( listViewBase . Items . Count - 1 ) )
@@ -58,7 +58,7 @@ public static async Task SmoothScrollIntoViewWithIndexAsync(this ListViewBase li
58
58
59
59
var tcs = new TaskCompletionSource < object > ( ) ;
60
60
61
- void ViewChanged ( object obj , ScrollViewerViewChangedEventArgs args ) => tcs . TrySetResult ( result : null ) ;
61
+ void ViewChanged ( object _ , ScrollViewerViewChangedEventArgs __ ) => tcs . TrySetResult ( result : default ) ;
62
62
63
63
try
64
64
{
@@ -80,20 +80,7 @@ public static async Task SmoothScrollIntoViewWithIndexAsync(this ListViewBase li
80
80
// Scrolling back to previous position
81
81
if ( isVirtualizing )
82
82
{
83
- var tcs = new TaskCompletionSource < object > ( ) ;
84
-
85
- void ViewChanged ( object obj , ScrollViewerViewChangedEventArgs args ) => tcs . TrySetResult ( result : null ) ;
86
-
87
- try
88
- {
89
- scrollViewer . ViewChanged += ViewChanged ;
90
- scrollViewer . ChangeView ( previousXOffset , previousYOffset , zoomFactor : null , disableAnimation : true ) ;
91
- await tcs . Task ;
92
- }
93
- finally
94
- {
95
- scrollViewer . ViewChanged -= ViewChanged ;
96
- }
83
+ await scrollViewer . ChangeViewAsync ( previousXOffset , previousYOffset , zoomFactor : null , disableAnimation : true ) ;
97
84
}
98
85
99
86
var listViewBaseWidth = listViewBase . ActualWidth ;
@@ -185,7 +172,7 @@ public static async Task SmoothScrollIntoViewWithIndexAsync(this ListViewBase li
185
172
}
186
173
}
187
174
188
- scrollViewer . ChangeView ( finalXPosition , finalYPosition , zoomFactor : null , disableAnimation ) ;
175
+ await scrollViewer . ChangeViewAsync ( finalXPosition , finalYPosition , zoomFactor : null , disableAnimation ) ;
189
176
}
190
177
191
178
/// <summary>
@@ -198,10 +185,68 @@ public static async Task SmoothScrollIntoViewWithIndexAsync(this ListViewBase li
198
185
/// <param name="scrollIfVisibile">Set true to disable scrolling when the corresponding item is in view</param>
199
186
/// <param name="additionalHorizontalOffset">Adds additional horizontal offset</param>
200
187
/// <param name="additionalVerticalOffset">Adds additional vertical offset</param>
201
- /// <returns>Note: Even though this return <see cref="Task"/>, it will not wait until the scrolling completes </returns>
188
+ /// <returns>Returns <see cref="Task"/> that completes after scrolling</returns>
202
189
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 )
203
190
{
204
191
await SmoothScrollIntoViewWithIndexAsync ( listViewBase , listViewBase . Items . IndexOf ( item ) , itemPlacement , disableAnimation , scrollIfVisibile , additionalHorizontalOffset , additionalVerticalOffset ) ;
205
192
}
193
+
194
+ /// <summary>
195
+ /// Changes the view of <see cref="ScrollViewer"/> asynchronous.
196
+ /// </summary>
197
+ /// <param name="scrollViewer">The scroll viewer.</param>
198
+ /// <param name="horizontalOffset">The horizontal offset.</param>
199
+ /// <param name="verticalOffset">The vertical offset.</param>
200
+ /// <param name="zoomFactor">The zoom factor.</param>
201
+ /// <param name="disableAnimation">if set to <c>true</c> disable animation.</param>
202
+ private static async Task ChangeViewAsync ( this ScrollViewer scrollViewer , double ? horizontalOffset , double ? verticalOffset , float ? zoomFactor , bool disableAnimation )
203
+ {
204
+ if ( horizontalOffset > scrollViewer . ScrollableWidth )
205
+ {
206
+ horizontalOffset = scrollViewer . ScrollableWidth ;
207
+ }
208
+ else if ( horizontalOffset < 0 )
209
+ {
210
+ horizontalOffset = 0 ;
211
+ }
212
+
213
+ if ( verticalOffset > scrollViewer . ScrollableHeight )
214
+ {
215
+ verticalOffset = scrollViewer . ScrollableHeight ;
216
+ }
217
+ else if ( verticalOffset < 0 )
218
+ {
219
+ verticalOffset = 0 ;
220
+ }
221
+
222
+ // MUST check this and return immediately, otherwise this async task will never complete because ViewChanged event won't get triggered
223
+ if ( horizontalOffset == scrollViewer . HorizontalOffset && verticalOffset == scrollViewer . VerticalOffset )
224
+ {
225
+ return ;
226
+ }
227
+
228
+ var tcs = new TaskCompletionSource < object > ( ) ;
229
+
230
+ void ViewChanged ( object _ , ScrollViewerViewChangedEventArgs e )
231
+ {
232
+ if ( e . IsIntermediate )
233
+ {
234
+ return ;
235
+ }
236
+
237
+ tcs . TrySetResult ( result : default ) ;
238
+ }
239
+
240
+ try
241
+ {
242
+ scrollViewer . ViewChanged += ViewChanged ;
243
+ scrollViewer . ChangeView ( horizontalOffset , verticalOffset , zoomFactor , disableAnimation ) ;
244
+ await tcs . Task ;
245
+ }
246
+ finally
247
+ {
248
+ scrollViewer . ViewChanged -= ViewChanged ;
249
+ }
250
+ }
206
251
}
207
252
}
0 commit comments