@@ -23,6 +23,13 @@ namespace Avalonia.Controls.UnitTests
2323{
2424 public class VirtualizingStackPanelTests : ScopedTestBase
2525 {
26+ private static FuncDataTemplate < ItemWithHeight > CanvasWithHeightTemplate = new ( ( _ , _ ) =>
27+ new Canvas
28+ {
29+ Width = 100 ,
30+ [ ! Layoutable . HeightProperty ] = new Binding ( "Height" ) ,
31+ } ) ;
32+
2633 [ Fact ]
2734 public void Creates_Initial_Items ( )
2835 {
@@ -744,14 +751,7 @@ public void Scrolling_Down_With_Larger_Element_Does_Not_Cause_Jump_And_Arrives_A
744751 var items = Enumerable . Range ( 0 , 1000 ) . Select ( x => new ItemWithHeight ( x ) ) . ToList ( ) ;
745752 items [ 20 ] . Height = 200 ;
746753
747- var itemTemplate = new FuncDataTemplate < ItemWithHeight > ( ( x , _ ) =>
748- new Canvas
749- {
750- Width = 100 ,
751- [ ! Canvas . HeightProperty ] = new Binding ( "Height" ) ,
752- } ) ;
753-
754- var ( target , scroll , itemsControl ) = CreateTarget ( items : items , itemTemplate : itemTemplate ) ;
754+ var ( target , scroll , itemsControl ) = CreateTarget ( items : items , itemTemplate : CanvasWithHeightTemplate ) ;
755755
756756 var index = target . FirstRealizedIndex ;
757757
@@ -780,14 +780,7 @@ public void Scrolling_Up_To_Larger_Element_Does_Not_Cause_Jump()
780780 var items = Enumerable . Range ( 0 , 100 ) . Select ( x => new ItemWithHeight ( x ) ) . ToList ( ) ;
781781 items [ 20 ] . Height = 200 ;
782782
783- var itemTemplate = new FuncDataTemplate < ItemWithHeight > ( ( x , _ ) =>
784- new Canvas
785- {
786- Width = 100 ,
787- [ ! Canvas . HeightProperty ] = new Binding ( "Height" ) ,
788- } ) ;
789-
790- var ( target , scroll , itemsControl ) = CreateTarget ( items : items , itemTemplate : itemTemplate ) ;
783+ var ( target , scroll , itemsControl ) = CreateTarget ( items : items , itemTemplate : CanvasWithHeightTemplate ) ;
791784
792785 // Scroll past the larger element.
793786 scroll . Offset = new Vector ( 0 , 600 ) ;
@@ -817,14 +810,7 @@ public void Scrolling_Up_To_Smaller_Element_Does_Not_Cause_Jump()
817810 var items = Enumerable . Range ( 0 , 100 ) . Select ( x => new ItemWithHeight ( x , 30 ) ) . ToList ( ) ;
818811 items [ 20 ] . Height = 25 ;
819812
820- var itemTemplate = new FuncDataTemplate < ItemWithHeight > ( ( x , _ ) =>
821- new Canvas
822- {
823- Width = 100 ,
824- [ ! Canvas . HeightProperty ] = new Binding ( "Height" ) ,
825- } ) ;
826-
827- var ( target , scroll , itemsControl ) = CreateTarget ( items : items , itemTemplate : itemTemplate ) ;
813+ var ( target , scroll , itemsControl ) = CreateTarget ( items : items , itemTemplate : CanvasWithHeightTemplate ) ;
828814
829815 // Scroll past the larger element.
830816 scroll . Offset = new Vector ( 0 , 25 * items [ 0 ] . Height ) ;
@@ -1154,6 +1140,58 @@ public void ScrollIntoView_With_TargetRect_Outside_Viewport_Should_Scroll_To_Ite
11541140 Assert . Equal ( 9901 , scroll . Offset . X ) ;
11551141 }
11561142
1143+ [ Fact ]
1144+ public void ScrollIntoView_Correctly_Scrolls_Down_To_A_Page_Of_Smaller_Items ( )
1145+ {
1146+ using var app = App ( ) ;
1147+
1148+ // First 10 items have height of 20, next 10 have height of 10.
1149+ var items = Enumerable . Range ( 0 , 20 ) . Select ( x => new ItemWithHeight ( x , ( ( 29 - x ) / 10 ) * 10 ) ) ;
1150+ var ( target , scroll , itemsControl ) = CreateTarget ( items : items , itemTemplate : CanvasWithHeightTemplate ) ;
1151+
1152+ // Scroll the last item into view.
1153+ target . ScrollIntoView ( 19 ) ;
1154+
1155+ // At the time of the scroll, the average item height is 20, so the requested item
1156+ // should be placed at 380 (19 * 20) which therefore results in an extent of 390 to
1157+ // accommodate the item height of 10. This is obviously not a perfect answer, but
1158+ // it's the best we can do without knowing the actual item heights.
1159+ var container = Assert . IsType < ContentPresenter > ( target . ContainerFromIndex ( 19 ) ) ;
1160+ Assert . Equal ( new Rect ( 0 , 380 , 100 , 10 ) , container . Bounds ) ;
1161+ Assert . Equal ( new Size ( 100 , 100 ) , scroll . Viewport ) ;
1162+ Assert . Equal ( new Size ( 100 , 390 ) , scroll . Extent ) ;
1163+ Assert . Equal ( new Vector ( 0 , 290 ) , scroll . Offset ) ;
1164+
1165+ // Items 10-19 should be visible.
1166+ AssertRealizedItems ( target , itemsControl , 10 , 10 ) ;
1167+ }
1168+
1169+ [ Fact ]
1170+ public void ScrollIntoView_Correctly_Scrolls_Down_To_A_Page_Of_Larger_Items ( )
1171+ {
1172+ using var app = App ( ) ;
1173+
1174+ // First 10 items have height of 10, next 10 have height of 20.
1175+ var items = Enumerable . Range ( 0 , 20 ) . Select ( x => new ItemWithHeight ( x , ( ( x / 10 ) + 1 ) * 10 ) ) ;
1176+ var ( target , scroll , itemsControl ) = CreateTarget ( items : items , itemTemplate : CanvasWithHeightTemplate ) ;
1177+
1178+ // Scroll the last item into view.
1179+ target . ScrollIntoView ( 19 ) ;
1180+
1181+ // At the time of the scroll, the average item height is 10, so the requested item
1182+ // should be placed at 190 (19 * 10) which therefore results in an extent of 210 to
1183+ // accommodate the item height of 20. This is obviously not a perfect answer, but
1184+ // it's the best we can do without knowing the actual item heights.
1185+ var container = Assert . IsType < ContentPresenter > ( target . ContainerFromIndex ( 19 ) ) ;
1186+ Assert . Equal ( new Rect ( 0 , 190 , 100 , 20 ) , container . Bounds ) ;
1187+ Assert . Equal ( new Size ( 100 , 100 ) , scroll . Viewport ) ;
1188+ Assert . Equal ( new Size ( 100 , 210 ) , scroll . Extent ) ;
1189+ Assert . Equal ( new Vector ( 0 , 110 ) , scroll . Offset ) ;
1190+
1191+ // Items 15-19 should be visible.
1192+ AssertRealizedItems ( target , itemsControl , 15 , 5 ) ;
1193+ }
1194+
11571195 private static IReadOnlyList < int > GetRealizedIndexes ( VirtualizingStackPanel target , ItemsControl itemsControl )
11581196 {
11591197 return target . GetRealizedElements ( )
@@ -1176,6 +1214,11 @@ private static void AssertRealizedItems(
11761214 . OrderBy ( x => x )
11771215 . ToList ( ) ;
11781216 Assert . Equal ( Enumerable . Range ( firstIndex , count ) , childIndexes ) ;
1217+
1218+ var visibleChildren = target . Children
1219+ . Where ( x => x . IsVisible )
1220+ . ToList ( ) ;
1221+ Assert . Equal ( count , visibleChildren . Count ) ;
11791222 }
11801223
11811224 private static void AssertRealizedControlItems < TContainer > (
0 commit comments