22// The .NET Foundation licenses this file to you under the MIT license.
33// See the LICENSE file in the project root for more information.
44
5- using System ;
65using System . Collections . Generic ;
6+ using System . Linq ;
77using Windows . Foundation ;
88using Windows . UI . Xaml ;
99using Windows . UI . Xaml . Controls ;
@@ -129,135 +129,37 @@ private static void LayoutPropertyChanged(DependencyObject d, DependencyProperty
129129 }
130130 }
131131
132+ private readonly List < Row > _rows = new List < Row > ( ) ;
133+
132134 /// <inheritdoc />
133135 protected override Size MeasureOverride ( Size availableSize )
134136 {
135- availableSize . Width = availableSize . Width - Padding . Left - Padding . Right ;
136- availableSize . Height = availableSize . Height - Padding . Top - Padding . Bottom ;
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 lineMeasure = UvMeasure . Zero ;
141-
137+ var childAvailableSize = new Size (
138+ availableSize . Width - Padding . Left - Padding . Right ,
139+ availableSize . Height - Padding . Top - Padding . Bottom ) ;
142140 foreach ( var child in Children )
143141 {
144- child . Measure ( availableSize ) ;
145- var currentMeasure = new UvMeasure ( Orientation , child . DesiredSize ) ;
146- if ( currentMeasure . U == 0 )
147- {
148- continue ; // ignore collapsed items
149- }
150-
151- // if this is the first item, do not add spacing. Spacing is added to the "left"
152- double uChange = lineMeasure . U == 0
153- ? currentMeasure . U
154- : currentMeasure . U + spacingMeasure . U ;
155- if ( parentMeasure . U >= uChange + lineMeasure . U )
156- {
157- lineMeasure . U += uChange ;
158- lineMeasure . V = Math . Max ( lineMeasure . V , currentMeasure . V ) ;
159- }
160- else
161- {
162- // new line should be added
163- // to get the max U to provide it correctly to ui width ex: ---| or -----|
164- totalMeasure . U = Math . Max ( lineMeasure . U , totalMeasure . U ) ;
165- totalMeasure . V += lineMeasure . V + spacingMeasure . V ;
166-
167- // if the next new row still can handle more controls
168- if ( parentMeasure . U > currentMeasure . U )
169- {
170- // set lineMeasure initial values to the currentMeasure to be calculated later on the new loop
171- lineMeasure = currentMeasure ;
172- }
173-
174- // the control will take one row alone
175- else
176- {
177- // validate the new control measures
178- totalMeasure . U = Math . Max ( currentMeasure . U , totalMeasure . U ) ;
179- totalMeasure . V += currentMeasure . V ;
180-
181- // add new empty line
182- lineMeasure = UvMeasure . Zero ;
183- }
184- }
142+ child . Measure ( childAvailableSize ) ;
185143 }
186144
187- // update value with the last line
188- // if the last loop is (parentMeasure.U > currentMeasure.U + lineMeasure.U) the total isn't calculated then calculate it
189- // if the last loop is (parentMeasure.U > currentMeasure.U) the currentMeasure isn't added to the total so add it here
190- // for the last condition it is zeros so adding it will make no difference
191- // this way is faster than an if condition in every loop for checking the last item
192- totalMeasure . U = Math . Max ( lineMeasure . U , totalMeasure . U ) ;
193- totalMeasure . V += lineMeasure . V ;
194-
195- totalMeasure . U = Math . Ceiling ( totalMeasure . U ) ;
196-
197- return Orientation == Orientation . Horizontal ? new Size ( totalMeasure . U , totalMeasure . V ) : new Size ( totalMeasure . V , totalMeasure . U ) ;
145+ var requiredSize = UpdateRows ( availableSize ) ;
146+ return requiredSize ;
198147 }
199148
200149 /// <inheritdoc />
201150 protected override Size ArrangeOverride ( Size finalSize )
202151 {
203- var rows = new List < Row > ( ) ;
204- if ( Children . Count > 0 )
152+ if ( finalSize != DesiredSize )
205153 {
206- var parentMeasure = new UvMeasure ( Orientation , finalSize . Width , finalSize . Height ) ;
207- var spacingMeasure = new UvMeasure ( Orientation , HorizontalSpacing , VerticalSpacing ) ;
208- var paddingStart = new UvMeasure ( Orientation , Padding . Left , Padding . Top ) ;
209- var paddingEnd = new UvMeasure ( Orientation , Padding . Right , Padding . Bottom ) ;
210- var position = new UvMeasure ( Orientation , Padding . Left , Padding . Top ) ;
211-
212- var currentRow = new Row ( new List < UvRect > ( ) , default ) ;
213- void Arrange ( UIElement child , bool isLast = false )
214- {
215- var desiredMeasure = new UvMeasure ( Orientation , child . DesiredSize ) ;
216- if ( desiredMeasure . U == 0 )
217- {
218- return ; // if an item is collapsed, avoid adding the spacing
219- }
220-
221- if ( ( desiredMeasure . U + position . U + paddingEnd . U ) > parentMeasure . U )
222- {
223- // next row!
224- position . U = paddingStart . U ;
225- position . V += currentRow . Size . V + spacingMeasure . V ;
226-
227- rows . Add ( currentRow ) ;
228- currentRow = new Row ( new List < UvRect > ( ) , default ) ;
229- }
230-
231- // Stretch the last item to fill the available space
232- if ( isLast )
233- {
234- desiredMeasure . U = parentMeasure . U - position . U ;
235- }
236-
237- currentRow . Add ( position , desiredMeasure ) ;
238-
239- // adjust the location for the next items
240- position . U += desiredMeasure . U + spacingMeasure . U ;
241- }
242-
243- var lastIndex = Children . Count - 1 ;
244- for ( var i = 0 ; i < lastIndex ; i ++ )
245- {
246- Arrange ( Children [ i ] ) ;
247- }
248-
249- Arrange ( Children [ lastIndex ] , StretchChild == StretchChild . Last ) ;
250- if ( currentRow . ChildrenRects . Count > 0 )
251- {
252- rows . Add ( currentRow ) ;
253- }
154+ // We haven't received our desired size. We need to refresh the rows.
155+ finalSize = UpdateRows ( finalSize ) ;
254156 }
255157
256- if ( rows . Count > 0 )
158+ if ( _rows . Count > 0 )
257159 {
258160 // Now that we have all the data, we do the actual arrange pass
259161 var childIndex = 0 ;
260- foreach ( var row in rows )
162+ foreach ( var row in _rows )
261163 {
262164 foreach ( var rect in row . ChildrenRects )
263165 {
@@ -276,5 +178,73 @@ void Arrange(UIElement child, bool isLast = false)
276178
277179 return finalSize ;
278180 }
181+
182+ private Size UpdateRows ( Size finalSize )
183+ {
184+ _rows . Clear ( ) ;
185+ if ( Children . Count == 0 )
186+ {
187+ return Size . Empty ;
188+ }
189+
190+ var parentMeasure = new UvMeasure ( Orientation , finalSize . Width , finalSize . Height ) ;
191+ var spacingMeasure = new UvMeasure ( Orientation , HorizontalSpacing , VerticalSpacing ) ;
192+ var paddingStart = new UvMeasure ( Orientation , Padding . Left , Padding . Top ) ;
193+ var paddingEnd = new UvMeasure ( Orientation , Padding . Right , Padding . Bottom ) ;
194+ var position = new UvMeasure ( Orientation , Padding . Left , Padding . Top ) ;
195+
196+ var currentRow = new Row ( new List < UvRect > ( ) , default ) ;
197+ void Arrange ( UIElement child , bool isLast = false )
198+ {
199+ var desiredMeasure = new UvMeasure ( Orientation , child . DesiredSize ) ;
200+ if ( desiredMeasure . U == 0 )
201+ {
202+ return ; // if an item is collapsed, avoid adding the spacing
203+ }
204+
205+ if ( ( desiredMeasure . U + position . U + paddingEnd . U ) > parentMeasure . U )
206+ {
207+ // next row!
208+ position . U = paddingStart . U ;
209+ position . V += currentRow . Size . V + spacingMeasure . V ;
210+
211+ _rows . Add ( currentRow ) ;
212+ currentRow = new Row ( new List < UvRect > ( ) , default ) ;
213+ }
214+
215+ // Stretch the last item to fill the available space
216+ if ( isLast )
217+ {
218+ desiredMeasure . U = parentMeasure . U - position . U ;
219+ }
220+
221+ currentRow . Add ( position , desiredMeasure ) ;
222+
223+ // adjust the location for the next items
224+ position . U += desiredMeasure . U + spacingMeasure . U ;
225+ }
226+
227+ var lastIndex = Children . Count - 1 ;
228+ for ( var i = 0 ; i < lastIndex ; i ++ )
229+ {
230+ Arrange ( Children [ i ] ) ;
231+ }
232+
233+ Arrange ( Children [ lastIndex ] , StretchChild == StretchChild . Last ) ;
234+ if ( currentRow . ChildrenRects . Count > 0 )
235+ {
236+ _rows . Add ( currentRow ) ;
237+ }
238+
239+ if ( _rows . Count == 0 )
240+ {
241+ return Size . Empty ;
242+ }
243+
244+ var lastRowRect = _rows . Last ( ) . Rect . ToRect ( Orientation ) ;
245+ return new Size (
246+ lastRowRect . Bottom + Padding . Bottom ,
247+ lastRowRect . Right + Padding . Right ) ;
248+ }
279249 }
280250}
0 commit comments