2
2
// The .NET Foundation licenses this file to you under the MIT license.
3
3
// See the LICENSE file in the project root for more information.
4
4
5
+ using System ;
5
6
using Microsoft . UI . Xaml . Controls ;
6
7
using System . Collections . Specialized ;
8
+ using Windows . Foundation ;
9
+ using Microsoft . UI . Xaml ;
7
10
8
11
namespace CommunityToolkit . WinUI . Controls ;
9
12
@@ -20,8 +23,8 @@ public class WrapLayout : VirtualizingLayout
20
23
/// </summary>
21
24
public double HorizontalSpacing
22
25
{
23
- get { return ( double ) GetValue ( HorizontalSpacingProperty ) ; }
24
- set { SetValue ( HorizontalSpacingProperty , value ) ; }
26
+ get => ( double ) GetValue ( HorizontalSpacingProperty ) ;
27
+ set => SetValue ( HorizontalSpacingProperty , value ) ;
25
28
}
26
29
27
30
/// <summary>
@@ -40,8 +43,8 @@ public double HorizontalSpacing
40
43
/// </summary>
41
44
public double VerticalSpacing
42
45
{
43
- get { return ( double ) GetValue ( VerticalSpacingProperty ) ; }
44
- set { SetValue ( VerticalSpacingProperty , value ) ; }
46
+ get => ( double ) GetValue ( VerticalSpacingProperty ) ;
47
+ set => SetValue ( VerticalSpacingProperty , value ) ;
45
48
}
46
49
47
50
/// <summary>
@@ -61,8 +64,8 @@ public double VerticalSpacing
61
64
/// </summary>
62
65
public Orientation Orientation
63
66
{
64
- get { return ( Orientation ) GetValue ( OrientationProperty ) ; }
65
- set { SetValue ( OrientationProperty , value ) ; }
67
+ get => ( Orientation ) GetValue ( OrientationProperty ) ;
68
+ set => SetValue ( OrientationProperty , value ) ;
66
69
}
67
70
68
71
/// <summary>
@@ -87,8 +90,7 @@ private static void LayoutPropertyChanged(DependencyObject d, DependencyProperty
87
90
/// <inheritdoc />
88
91
protected override void InitializeForContextCore ( VirtualizingLayoutContext context )
89
92
{
90
- var state = new WrapLayoutState ( context ) ;
91
- context . LayoutState = state ;
93
+ context . LayoutState = new WrapLayoutState ( context ) ;
92
94
base . InitializeForContextCore ( context ) ;
93
95
}
94
96
@@ -110,7 +112,7 @@ protected override void OnItemsChangedCore(VirtualizingLayoutContext context, ob
110
112
state . RemoveFromIndex ( args . NewStartingIndex ) ;
111
113
break ;
112
114
case NotifyCollectionChangedAction . Move :
113
- int minIndex = Math . Min ( args . NewStartingIndex , args . OldStartingIndex ) ;
115
+ var minIndex = Math . Min ( args . NewStartingIndex , args . OldStartingIndex ) ;
114
116
state . RemoveFromIndex ( minIndex ) ;
115
117
116
118
state . RecycleElementAt ( args . OldStartingIndex ) ;
@@ -134,50 +136,40 @@ protected override void OnItemsChangedCore(VirtualizingLayoutContext context, ob
134
136
/// <inheritdoc />
135
137
protected override Size MeasureOverride ( VirtualizingLayoutContext context , Size availableSize )
136
138
{
137
- var totalMeasure = UvMeasure . Zero ;
138
- var parentMeasure = new UvMeasure ( Orientation , availableSize . Width , availableSize . Height ) ;
139
- var spacingMeasure = new UvMeasure ( Orientation , HorizontalSpacing , VerticalSpacing ) ;
140
- var realizationBounds = new UvBounds ( Orientation , context . RealizationRect ) ;
141
- var position = UvMeasure . Zero ;
139
+ var parentMeasure = new UvMeasure ( Orientation , availableSize ) ;
140
+ var spacingMeasure = new UvMeasure ( Orientation , new Size ( HorizontalSpacing , VerticalSpacing ) ) ;
142
141
143
142
var state = ( WrapLayoutState ) context . LayoutState ;
144
143
if ( state . Orientation != Orientation )
145
144
{
146
145
state . SetOrientation ( Orientation ) ;
147
146
}
148
147
149
- if ( spacingMeasure . Equals ( state . Spacing ) == false )
148
+ if ( spacingMeasure != state . Spacing || state . AvailableU != parentMeasure . U )
150
149
{
151
150
state . ClearPositions ( ) ;
152
151
state . Spacing = spacingMeasure ;
153
- }
154
-
155
- if ( state . AvailableU != parentMeasure . U )
156
- {
157
- state . ClearPositions ( ) ;
158
152
state . AvailableU = parentMeasure . U ;
159
153
}
160
154
161
155
double currentV = 0 ;
162
- for ( int i = 0 ; i < context . ItemCount ; i ++ )
156
+ var realizationBounds = new UvBounds ( Orientation , context . RealizationRect ) ;
157
+ var position = new UvMeasure ( ) ;
158
+ for ( var i = 0 ; i < context . ItemCount ; ++ i )
163
159
{
164
- bool measured = false ;
165
- WrapItem item = state . GetItemAt ( i ) ;
166
- if ( item . Measure == null )
160
+ var measured = false ;
161
+ var item = state . GetItemAt ( i ) ;
162
+ if ( item . Measure is null )
167
163
{
168
164
item . Element = context . GetOrCreateElementAt ( i ) ;
169
165
item . Element . Measure ( availableSize ) ;
170
- item . Measure = new UvMeasure ( Orientation , item . Element . DesiredSize . Width , item . Element . DesiredSize . Height ) ;
166
+ item . Measure = new UvMeasure ( Orientation , item . Element . DesiredSize ) ;
171
167
measured = true ;
172
168
}
173
169
174
- UvMeasure currentMeasure = item . Measure . Value ;
175
- if ( currentMeasure . U == 0 )
176
- {
177
- continue ; // ignore collapsed items
178
- }
170
+ var currentMeasure = item . Measure . Value ;
179
171
180
- if ( item . Position == null )
172
+ if ( item . Position is null )
181
173
{
182
174
if ( parentMeasure . U < position . U + currentMeasure . U )
183
175
{
@@ -192,20 +184,22 @@ protected override Size MeasureOverride(VirtualizingLayoutContext context, Size
192
184
193
185
position = item . Position . Value ;
194
186
195
- double vEnd = position . V + currentMeasure . V ;
187
+ var vEnd = position . V + currentMeasure . V ;
196
188
if ( vEnd < realizationBounds . VMin )
197
189
{
198
190
// Item is "above" the bounds
199
- if ( item . Element != null )
191
+ if ( item . Element is not null )
200
192
{
201
193
context . RecycleElement ( item . Element ) ;
202
194
item . Element = null ;
203
195
}
196
+
197
+ continue ;
204
198
}
205
199
else if ( position . V > realizationBounds . VMax )
206
200
{
207
201
// Item is "below" the bounds.
208
- if ( item . Element != null )
202
+ if ( item . Element is not null )
209
203
{
210
204
context . RecycleElement ( item . Element ) ;
211
205
item . Element = null ;
@@ -214,14 +208,14 @@ protected override Size MeasureOverride(VirtualizingLayoutContext context, Size
214
208
// We don't need to measure anything below the bounds
215
209
break ;
216
210
}
217
- else if ( measured == false )
211
+ else if ( ! measured )
218
212
{
219
213
// Always measure elements that are within the bounds
220
214
item . Element = context . GetOrCreateElementAt ( i ) ;
221
215
item . Element . Measure ( availableSize ) ;
222
216
223
- currentMeasure = new UvMeasure ( Orientation , item . Element . DesiredSize . Width , item . Element . DesiredSize . Height ) ;
224
- if ( currentMeasure . Equals ( item . Measure ) == false )
217
+ currentMeasure = new UvMeasure ( Orientation , item . Element . DesiredSize ) ;
218
+ if ( currentMeasure != item . Measure )
225
219
{
226
220
// this item changed size; we need to recalculate layout for everything after this
227
221
state . RemoveFromIndex ( i + 1 ) ;
@@ -249,70 +243,43 @@ protected override Size MeasureOverride(VirtualizingLayoutContext context, Size
249
243
// if the last loop is (parentMeasure.U > currentMeasure.U) the currentMeasure isn't added to the total so add it here
250
244
// for the last condition it is zeros so adding it will make no difference
251
245
// this way is faster than an if condition in every loop for checking the last item
252
- totalMeasure . U = parentMeasure . U ;
253
-
254
246
// Propagating an infinite size causes a crash. This can happen if the parent is scrollable and infinite in the opposite
255
247
// axis to the panel. Clearing to zero prevents the crash.
256
- // This is likely an incorrect use of the control by the developer, however we need stability here so setting a default that wont crash.
257
- if ( double . IsInfinity ( totalMeasure . U ) )
258
- {
259
- totalMeasure . U = 0.0 ;
260
- }
248
+ // This is likely an incorrect use of the control by the developer, however we need stability here so setting a default that won't crash.
261
249
262
- totalMeasure . V = state . GetHeight ( ) ;
250
+ var totalMeasure = new UvMeasure
251
+ {
252
+ U = double . IsInfinity ( parentMeasure . U ) ? 0 : Math . Ceiling ( parentMeasure . U ) ,
253
+ V = state . GetHeight ( )
254
+ } ;
263
255
264
- totalMeasure . U = Math . Ceiling ( totalMeasure . U ) ;
265
- return Orientation == Orientation . Horizontal ? new Size ( ( float ) totalMeasure . U , ( float ) totalMeasure . V ) : new Size ( ( float ) totalMeasure . V , ( float ) totalMeasure . U ) ;
256
+ return totalMeasure . GetSize ( Orientation ) ;
266
257
}
267
258
268
259
/// <inheritdoc />
269
260
protected override Size ArrangeOverride ( VirtualizingLayoutContext context , Size finalSize )
270
261
{
271
262
if ( context . ItemCount > 0 )
272
263
{
273
- var parentMeasure = new UvMeasure ( Orientation , finalSize . Width , finalSize . Height ) ;
274
- var spacingMeasure = new UvMeasure ( Orientation , HorizontalSpacing , VerticalSpacing ) ;
275
264
var realizationBounds = new UvBounds ( Orientation , context . RealizationRect ) ;
276
265
277
266
var state = ( WrapLayoutState ) context . LayoutState ;
278
- bool Arrange ( WrapItem item , bool isLast = false )
267
+ bool ArrangeItem ( WrapItem item )
279
268
{
280
- if ( item . Measure . HasValue == false )
281
- {
282
- return false ;
283
- }
284
-
285
- if ( item . Position == null )
269
+ if ( item is { Measure : null } or { Position : null } )
286
270
{
287
271
return false ;
288
272
}
289
273
290
274
var desiredMeasure = item . Measure . Value ;
291
- if ( desiredMeasure . U == 0 )
292
- {
293
- return true ; // if an item is collapsed, avoid adding the spacing
294
- }
295
275
296
- UvMeasure position = item . Position . Value ;
276
+ var position = item . Position . Value ;
297
277
298
- // Stretch the last item to fill the available space
299
- if ( isLast )
300
- {
301
- desiredMeasure . U = parentMeasure . U - position . U ;
302
- }
303
-
304
- if ( ( ( position . V + desiredMeasure . V ) >= realizationBounds . VMin ) && ( position . V <= realizationBounds . VMax ) )
278
+ if ( realizationBounds . VMin <= position . V + desiredMeasure . V && position . V <= realizationBounds . VMax )
305
279
{
306
280
// place the item
307
- UIElement child = context . GetOrCreateElementAt ( item . Index ) ;
308
- if ( Orientation == Orientation . Horizontal )
309
- {
310
- child . Arrange ( new Rect ( ( float ) position . U , ( float ) position . V , ( float ) desiredMeasure . U , ( float ) desiredMeasure . V ) ) ;
311
- }
312
- else
313
- {
314
- child . Arrange ( new Rect ( ( float ) position . V , ( float ) position . U , ( float ) desiredMeasure . V , ( float ) desiredMeasure . U ) ) ;
315
- }
281
+ var child = context . GetOrCreateElementAt ( item . Index ) ;
282
+ child . Arrange ( new Rect ( position . GetPoint ( Orientation ) , desiredMeasure . GetSize ( Orientation ) ) ) ;
316
283
}
317
284
else if ( position . V > realizationBounds . VMax )
318
285
{
@@ -322,10 +289,9 @@ bool Arrange(WrapItem item, bool isLast = false)
322
289
return true ;
323
290
}
324
291
325
- for ( var i = 0 ; i < context . ItemCount ; i ++ )
292
+ for ( var i = 0 ; i < context . ItemCount ; ++ i )
326
293
{
327
- bool continueArranging = Arrange ( state . GetItemAt ( i ) ) ;
328
- if ( continueArranging == false )
294
+ if ( ! ArrangeItem ( state . GetItemAt ( i ) ) )
329
295
{
330
296
break ;
331
297
}
0 commit comments