Skip to content

Commit 471504b

Browse files
committed
optimized code + updated sample
1 parent 9696fc0 commit 471504b

File tree

4 files changed

+126
-61
lines changed

4 files changed

+126
-61
lines changed

Microsoft.Toolkit.Uwp.SampleApp/SamplePages/WrapPanel/WrapPanel.bind

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,16 @@
4646
<controls:WrapPanel Background="{ThemeResource Brush-Grey-04}"
4747
Padding="@[Padding:Thickness:0,0,0,0]@"
4848
VerticalSpacing="@[VerticalSpacing:Slider:5:0-200]@"
49-
HorizontalSpacing="@[HorizontalSpacing:Slider:5:0-200]@" />
49+
HorizontalSpacing="@[HorizontalSpacing:Slider:5:0-200]@"
50+
VerticalContentAlignment="@[VerticalContentAlignment:Enum:VerticalAlignment.Top]"/>
5051
</ItemsPanelTemplate>
5152
</ItemsControl.ItemsPanel>
53+
<ListView.ItemContainerStyle>
54+
<Style TargetType="ListViewItem">
55+
<Setter Property="VerticalContentAlignment" Value="Stretch" />
56+
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
57+
</Style>
58+
</ListView.ItemContainerStyle>
5259
</ListView>
5360
</Grid>
5461
</Page>

Microsoft.Toolkit.Uwp.SampleApp/SamplePages/WrapPanel/WrapPanelPage.xaml.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ private void AddButton_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
6464
{
6565
Category = "Remove",
6666
Thumbnail = "ms-appx:///Assets/Photos/BigFourSummerHeat.jpg",
67-
Width = Rand.Next(120, 180),
68-
Height = Rand.Next(80, 130)
67+
Width = Rand.Next(60, 180),
68+
Height = Rand.Next(40, 140)
6969
});
7070
}
7171

Microsoft.Toolkit.Uwp.UI.Controls/WrapPanel/WrapPanel.Data.cs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
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;
6+
using System.Collections.Generic;
57
using Windows.Foundation;
8+
using Windows.UI.Xaml;
69
using Windows.UI.Xaml.Controls;
710

811
namespace Microsoft.Toolkit.Uwp.UI.Controls
@@ -39,6 +42,87 @@ public UvMeasure(Orientation orientation, double width, double height)
3942
V = width;
4043
}
4144
}
45+
46+
public UvMeasure Add(double u, double v)
47+
=> new UvMeasure { U = U + u, V = V + v };
48+
}
49+
50+
private struct UvRect
51+
{
52+
public UvMeasure Position { get; set; }
53+
54+
public UvMeasure Size { get; set; }
55+
56+
public UvRect WithVerticalAlignment(VerticalAlignment alignment, double maxHeight)
57+
{
58+
switch (alignment)
59+
{
60+
case VerticalAlignment.Center:
61+
return new UvRect
62+
{
63+
Position = Position.Add(
64+
u: 0,
65+
v: Math.Max((maxHeight - Size.V) / 2.0, 0.0)),
66+
Size = Size,
67+
};
68+
case VerticalAlignment.Bottom:
69+
return new UvRect
70+
{
71+
Position = Position.Add(
72+
u: 0,
73+
v: Math.Max(maxHeight - Size.V, 0.0)),
74+
Size = Size,
75+
};
76+
case VerticalAlignment.Stretch:
77+
return new UvRect
78+
{
79+
Position = Position,
80+
Size = new UvMeasure { U = Size.U, V = maxHeight },
81+
};
82+
case VerticalAlignment.Top:
83+
default:
84+
return this;
85+
}
86+
}
87+
88+
public Rect ToRect(Orientation orientation)
89+
{
90+
switch (orientation)
91+
{
92+
case Orientation.Vertical:
93+
return new Rect(Position.V, Position.U, Size.V, Size.U);
94+
case Orientation.Horizontal:
95+
return new Rect(Position.U, Position.V, Size.U, Size.V);
96+
default:
97+
throw new NotSupportedException();
98+
}
99+
}
100+
}
101+
102+
private class Row
103+
{
104+
private readonly List<UvRect> _childrenRects;
105+
private UvMeasure _rowSize;
106+
107+
public Row()
108+
{
109+
_childrenRects = new List<UvRect>();
110+
_rowSize = UvMeasure.Zero;
111+
}
112+
113+
public IReadOnlyList<UvRect> ChildrenRects => _childrenRects;
114+
115+
/// <summary>
116+
/// Gets the size of the row.
117+
/// </summary>
118+
public UvMeasure Size => _rowSize;
119+
120+
public void Add(UvMeasure position, UvMeasure size)
121+
{
122+
_childrenRects.Add(new UvRect { Position = position, Size = size });
123+
_rowSize.U = Math.Max(_rowSize.U, position.U + size.U);
124+
_rowSize.V = Math.Max(_rowSize.V, size.V);
125+
}
42126
}
43127
}
44128
}

Microsoft.Toolkit.Uwp.UI.Controls/WrapPanel/WrapPanel.cs

Lines changed: 32 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
using System;
66
using System.Collections.Generic;
7-
using System.Linq;
87
using Windows.Foundation;
98
using Windows.UI.Xaml;
109
using Windows.UI.Xaml.Controls;
@@ -72,7 +71,7 @@ public VerticalAlignment VerticalContentAlignment
7271
nameof(VerticalContentAlignment),
7372
typeof(VerticalAlignment),
7473
typeof(WrapPanel),
75-
new PropertyMetadata(VerticalAlignment.Top));
74+
new PropertyMetadata(VerticalAlignment.Top, LayoutPropertyChanged));
7675

7776
/// <summary>
7877
/// Gets or sets the orientation of the WrapPanel.
@@ -219,6 +218,7 @@ protected override Size MeasureOverride(Size availableSize)
219218
/// <inheritdoc />
220219
protected override Size ArrangeOverride(Size finalSize)
221220
{
221+
var rows = new List<Row>();
222222
if (Children.Count > 0)
223223
{
224224
var parentMeasure = new UvMeasure(Orientation, finalSize.Width, finalSize.Height);
@@ -227,14 +227,10 @@ protected override Size ArrangeOverride(Size finalSize)
227227
var paddingEnd = new UvMeasure(Orientation, Padding.Right, Padding.Bottom);
228228
var position = new UvMeasure(Orientation, Padding.Left, Padding.Top);
229229

230-
var allMeasures = Children.Select(c => new UvMeasure(Orientation, c.DesiredSize)).ToList();
231-
var allData = new List<(UvMeasure position, UvMeasure size)>();
232-
233-
var currentV = 0.0;
234-
void Arrange(int childIndex, bool isLast = false)
230+
var currentRow = new Row();
231+
void Arrange(UIElement child, bool isLast = false)
235232
{
236-
var child = Children[childIndex];
237-
var desiredMeasure = allMeasures[childIndex];
233+
var desiredMeasure = new UvMeasure(Orientation, child.DesiredSize);
238234
if (desiredMeasure.U == 0)
239235
{
240236
return; // if an item is collapsed, avoid adding the spacing
@@ -244,8 +240,10 @@ void Arrange(int childIndex, bool isLast = false)
244240
{
245241
// next row!
246242
position.U = paddingStart.U;
247-
position.V += currentV + spacingMeasure.V;
248-
currentV = 0;
243+
position.V += currentRow.Size.V + spacingMeasure.V;
244+
245+
rows.Add(currentRow);
246+
currentRow = new Row();
249247
}
250248

251249
// Stretch the last item to fill the available space
@@ -254,69 +252,45 @@ void Arrange(int childIndex, bool isLast = false)
254252
desiredMeasure.U = parentMeasure.U - position.U;
255253
}
256254

257-
allData.Add((position, desiredMeasure));
255+
currentRow.Add(position, desiredMeasure);
258256

259257
// adjust the location for the next items
260258
position.U += desiredMeasure.U + spacingMeasure.U;
261-
currentV = Math.Max(desiredMeasure.V, currentV);
262259
}
263260

264261
var lastIndex = Children.Count - 1;
265262
for (var i = 0; i < lastIndex; i++)
266263
{
267-
Arrange(i);
264+
Arrange(Children[i]);
268265
}
269266

270-
Arrange(lastIndex, StretchChild == StretchChild.Last);
267+
Arrange(Children[lastIndex], StretchChild == StretchChild.Last);
268+
if (currentRow.ChildrenRects.Count > 0)
269+
{
270+
rows.Add(currentRow);
271+
}
272+
}
271273

274+
if (rows.Count > 0)
275+
{
272276
// Now that we have all the data, we do the actual arrange pass
273-
var lastArrangeV = -1.0;
274-
var maxRowHeight = 0.0;
275-
for (var i = 0; i < Children.Count; i++)
277+
var childIndex = 0;
278+
foreach (var row in rows)
276279
{
277-
// place the item
278-
var child = Children[i];
279-
(UvMeasure arrangePosition, UvMeasure arrangeMeasure) = allData[i];
280-
281-
if (lastArrangeV != arrangePosition.V)
282-
{
283-
// We are on a new row, we scan all the items to get the max row height
284-
maxRowHeight = allData
285-
.Skip(i) // ignore what has already being processed
286-
.TakeWhile(d => d.position.V == arrangePosition.V) // we are still on the same row
287-
.Max(d => d.size.V); // We want the max.
288-
}
289-
290-
if (Orientation == Orientation.Horizontal)
280+
foreach (var rect in row.ChildrenRects)
291281
{
292-
switch (VerticalContentAlignment)
282+
var child = Children[childIndex++];
283+
UvRect arrangeRect;
284+
if (Orientation == Orientation.Horizontal)
293285
{
294-
case VerticalAlignment.Center:
295-
{
296-
var vOffset = Math.Max((maxRowHeight - arrangeMeasure.V) / 2.0, 0.0);
297-
child.Arrange(new Rect(arrangePosition.U, arrangePosition.V + vOffset, arrangeMeasure.U, arrangeMeasure.V));
298-
break;
299-
}
300-
301-
case VerticalAlignment.Bottom:
302-
{
303-
var vOffset = Math.Max(maxRowHeight - arrangeMeasure.V, 0.0);
304-
child.Arrange(new Rect(arrangePosition.U, arrangePosition.V + vOffset, arrangeMeasure.U, arrangeMeasure.V));
305-
break;
306-
}
307-
308-
case VerticalAlignment.Stretch:
309-
child.Arrange(new Rect(arrangePosition.U, arrangePosition.V, arrangeMeasure.U, maxRowHeight));
310-
break;
311-
case VerticalAlignment.Top:
312-
default:
313-
child.Arrange(new Rect(arrangePosition.U, arrangePosition.V, arrangeMeasure.U, arrangeMeasure.V));
314-
break;
286+
arrangeRect = rect.WithVerticalAlignment(VerticalContentAlignment, row.Size.V);
315287
}
316-
}
317-
else
318-
{
319-
child.Arrange(new Rect(arrangePosition.V, arrangePosition.U, arrangeMeasure.V, arrangeMeasure.U));
288+
else
289+
{
290+
arrangeRect = rect;
291+
}
292+
293+
child.Arrange(arrangeRect.ToRect(Orientation));
320294
}
321295
}
322296
}

0 commit comments

Comments
 (0)