1818
1919using System ;
2020using System . Linq ;
21- using System . Windows . Controls ;
2221using System . Windows ;
22+ using System . Windows . Controls ;
2323//using Windows.Foundation;
2424//using Windows.UI.Xaml;
2525//using Windows.UI.Xaml.Controls;
@@ -38,7 +38,6 @@ public class StaggeredPanel : Panel
3838 /// </summary>
3939 public StaggeredPanel ( )
4040 {
41- //ProgressiveRenderingChunkSize = 1;
4241 //RegisterPropertyChangedCallback(Panel.HorizontalAlignmentProperty, OnHorizontalAlignmentChanged);
4342 }
4443
@@ -133,7 +132,7 @@ protected override Size MeasureOverride(Size availableSize)
133132 int numColumns = Math . Max ( 1 , availableWidth == double . PositiveInfinity ? - 1 : ( int ) Math . Floor ( availableWidth / _columnWidth ) ) ;
134133
135134 // adjust for column spacing on all columns expect the first
136- double totalWidth = _columnWidth + ( ( numColumns - 1 ) * ( _columnWidth + ColumnSpacing ) ) ;
135+ double totalWidth = GetTotalWidth ( numColumns ) ;
137136 if ( totalWidth > availableWidth )
138137 {
139138 numColumns -- ;
@@ -163,17 +162,14 @@ protected override Size MeasureOverride(Size availableSize)
163162 child . Measure ( new Size ( availableWidth , availableHeight ) ) ;
164163 var elementSize = child . DesiredSize ;
165164
166- double newHeight ;
167- int heightDefiningColumnIndex ;
168- var columnIndex = GetPlacementInformations ( columnHeights , elementSize , out newHeight , out heightDefiningColumnIndex ) ;
169165 int elementColumnSpan = GetElementColumnSpan ( elementSize . Width ) ;
166+ var columnIndex = CalculatePlacement ( columnHeights , elementSize , elementColumnSpan , out double newHeight , out _ ) ;
170167
171- for ( int k = 0 ; k < elementColumnSpan ; ++ k )
168+ for ( int k = 0 ; k < elementColumnSpan && columnIndex + k < numColumns ; ++ k )
172169 {
173170 columnHeights [ columnIndex + k ] = newHeight + ( itemsPerColumn [ columnIndex ] > 0 ? RowSpacing : 0 ) ;
174171 itemsPerColumn [ columnIndex + k ] ++ ;
175172 }
176- itemsPerColumn [ columnIndex ] ++ ;
177173 }
178174
179175 double desiredHeight = columnHeights . Max ( ) ;
@@ -189,7 +185,7 @@ protected override Size ArrangeOverride(Size finalSize)
189185 int numColumns = Math . Max ( 1 , ( int ) Math . Floor ( finalSize . Width / _columnWidth ) ) ;
190186
191187 // adjust for horizontal spacing on all columns expect the first
192- double totalWidth = _columnWidth + ( ( numColumns - 1 ) * ( _columnWidth + ColumnSpacing ) ) ;
188+ double totalWidth = GetTotalWidth ( numColumns ) ;
193189 #region Explanation for the -0.01 in the if below:
194190 // we compare to totalWidth -0.01 because such a small overflow wouldn't be visible and it is still a likely scenario:
195191 // If we are Stretched, MeasureOverride will have changed _columnWidth to availableWidth/numColumns, which can be rounded higher than the actual value.
@@ -201,7 +197,7 @@ protected override Size ArrangeOverride(Size finalSize)
201197 numColumns -- ;
202198
203199 // Need to recalculate the totalWidth for a correct horizontal offset
204- totalWidth = _columnWidth + ( ( numColumns - 1 ) * ( _columnWidth + ColumnSpacing ) ) ;
200+ totalWidth = GetTotalWidth ( numColumns ) ;
205201 }
206202
207203 if ( HorizontalAlignment == HorizontalAlignment . Right )
@@ -218,27 +214,31 @@ protected override Size ArrangeOverride(Size finalSize)
218214
219215 for ( int i = 0 ; i < Children . Count ; i ++ )
220216 {
221-
222- var child = Children [ i ] ;
217+ var child = Children [ i ] as FrameworkElement ;
223218 var elementSize = child . DesiredSize ;
224219 double elementHeight = elementSize . Height ;
225220
226221 //get the element's column span:
227222 double elementWidth = elementSize . Width ;
228- int elementColumnsSpan = Math . Max ( 1 , ( int ) Math . Ceiling ( ( elementWidth - _columnWidth ) / ( _columnWidth + ColumnSpacing ) ) + 1 ) ;
229-
230- int columnIndex , heightDefiningColumnIndex ;
231- double newHeight ;
232-
233- columnIndex = GetPlacementInformations ( columnHeights , elementSize , out newHeight , out heightDefiningColumnIndex ) ;
223+ int elementColumnSpan = GetElementColumnSpan ( elementWidth ) ;
224+ int columnIndex = CalculatePlacement ( columnHeights , elementSize , elementColumnSpan , out double newHeight , out int heightDefiningColumnIndex ) ;
234225
235226 double itemHorizontalOffset = horizontalOffset + ( _columnWidth * columnIndex ) + ( ColumnSpacing * columnIndex ) ;
236227 double itemVerticalOffset = columnHeights [ heightDefiningColumnIndex ] + verticalOffset + ( RowSpacing * itemsPerColumn [ heightDefiningColumnIndex ] ) ;
237228
238- Rect bounds = new Rect ( itemHorizontalOffset , itemVerticalOffset , elementWidth , elementHeight ) ;
229+ if ( child . HorizontalAlignment == HorizontalAlignment . Right )
230+ {
231+ itemHorizontalOffset += GetTotalWidth ( elementColumnSpan ) - elementWidth ;
232+ }
233+ else if ( child . HorizontalAlignment == HorizontalAlignment . Center )
234+ {
235+ itemHorizontalOffset += ( GetTotalWidth ( elementColumnSpan ) - elementWidth ) / 2 ;
236+ }
237+
238+ var bounds = new Rect ( itemHorizontalOffset , itemVerticalOffset , elementWidth , elementHeight ) ;
239239 child . Arrange ( bounds ) ;
240240
241- for ( int k = 0 ; k < elementColumnsSpan ; ++ k )
241+ for ( int k = 0 ; k < elementColumnSpan && columnIndex + k < numColumns ; ++ k )
242242 {
243243 columnHeights [ columnIndex + k ] = newHeight ;
244244 itemsPerColumn [ columnIndex + k ] ++ ;
@@ -248,6 +248,11 @@ protected override Size ArrangeOverride(Size finalSize)
248248 return base . ArrangeOverride ( finalSize ) ;
249249 }
250250
251+ private double GetTotalWidth ( int numColumns )
252+ {
253+ return _columnWidth + ( ( numColumns - 1 ) * ( _columnWidth + ColumnSpacing ) ) ;
254+ }
255+
251256 private static void OnDesiredColumnWidthChanged ( DependencyObject d , DependencyPropertyChangedEventArgs e )
252257 {
253258 var panel = ( StaggeredPanel ) d ;
@@ -270,15 +275,11 @@ private int GetElementColumnSpan(double elementWidth)
270275 return Math . Max ( 1 , ( int ) Math . Ceiling ( ( elementWidth - _columnWidth ) / ( _columnWidth + ColumnSpacing ) ) + 1 ) ;
271276 }
272277
273- private int GetPlacementInformations ( double [ ] columnHeights , Size elementSize , out double newHeight , out int heightDefiningColumnIndex )
278+ private int CalculatePlacement ( double [ ] columnHeights , Size elementSize , int elementColumnSpan , out double newHeight , out int heightDefiningColumnIndex )
274279 {
275280 double elementHeight = elementSize . Height ;
276281
277- //get the element's column span:
278- double elementWidth = elementSize . Width ;
279- int elementColumnSpan = GetElementColumnSpan ( elementWidth ) ;
280-
281- int columnIndex = 0 ;
282+ int columnIndex ;
282283 if ( elementColumnSpan == 1 )
283284 {
284285 columnIndex = GetColumnIndex ( columnHeights ) ;
@@ -313,16 +314,24 @@ private int GetColumnIndex(double[] columnHeights, int elementColumnSpan, out do
313314 {
314315 if ( columnHeights . Length <= elementColumnSpan )
315316 {
316- // there is no option on where to put the element anyway so let's just return 0.
317317 bestHeight = columnHeights [ 0 ] ;
318318 heightDefiningColumnIndex = 0 ;
319+ for ( int i = 1 ; i < columnHeights . Length ; i ++ )
320+ {
321+ if ( columnHeights [ i ] > bestHeight )
322+ {
323+ heightDefiningColumnIndex = i ;
324+ bestHeight = columnHeights [ i ] ;
325+ }
326+ }
319327 return 0 ;
320328 }
321329
322- //initialization:
323330 int bestIndex = 0 ;
324331 bestHeight = double . MinValue ;
325332 heightDefiningColumnIndex = 0 ;
333+
334+ // Initialize bestHeight using the first valid span
326335 for ( int i = 0 ; i < elementColumnSpan ; ++ i )
327336 {
328337 if ( bestHeight < columnHeights [ i ] )
@@ -331,38 +340,42 @@ private int GetColumnIndex(double[] columnHeights, int elementColumnSpan, out do
331340 heightDefiningColumnIndex = i ;
332341 }
333342 }
334- int lastColumnIndex = columnHeights . Length - elementColumnSpan + 1 ;
343+
344+ int maxStartIndex = columnHeights . Length - elementColumnSpan ;
335345
336346 //we look for the set of columns that will allow us to put the element with the smallest vertical offset:
337- for ( int j = 1 ; j < lastColumnIndex ; j ++ )
347+ for ( int startIndex = 1 ; startIndex <= maxStartIndex ; ++ startIndex )
338348 {
339349 //We get the height of the new column to consider:
340- double newHeight = columnHeights [ j + elementColumnSpan - 1 ] ;
341- if ( newHeight > bestHeight )
350+ double newColumnHeight = columnHeights [ startIndex + elementColumnSpan - 1 ] ;
351+
352+ if ( newColumnHeight > bestHeight )
342353 {
343354 //we can exclude any set of columns that include the new column since at best, it won't be as good as what we have already found:
344- j += elementColumnSpan - 1 ; // -1 because the loop will also add 1.
355+ startIndex += elementColumnSpan - 1 ; // -1 because the loop will also add 1.
345356 continue ;
346357 }
347358
348359 //Calculate the height of the current set of columns:
349360 //Note: (perf) we could also read the height on j-1 and if that column's height is < bestHeight, it means that column was not the limiting one in the previous loop so no need to recalculate.
350361 double currentHeight = double . MinValue ;
351- for ( int i = 0 ; i < elementColumnSpan ; ++ i )
362+ int currentIndex = 0 ;
363+ for ( int offset = 0 ; offset < elementColumnSpan ; ++ offset )
352364 {
353- if ( currentHeight < columnHeights [ j + i ] )
365+ int index = startIndex + offset ;
366+ if ( currentHeight < columnHeights [ index ] )
354367 {
355- currentHeight = columnHeights [ j + i ] ;
356- heightDefiningColumnIndex = j + i ;
368+ currentHeight = columnHeights [ index ] ;
369+ currentIndex = index ;
357370 }
358371 }
359372
360373 if ( currentHeight < bestHeight )
361374 {
362375 bestHeight = currentHeight ;
363- bestIndex = j ;
376+ heightDefiningColumnIndex = currentIndex ;
377+ bestIndex = startIndex ;
364378 }
365-
366379 }
367380
368381 return bestIndex ;
0 commit comments