Implement ItemSpacing and LineSpacing in ElasticWrapPanel (#843)

* Initial plan

* Implement ItemSpacing and LineSpacing support for ElasticWrapPanel

Co-authored-by: rabbitism <14807942+rabbitism@users.noreply.github.com>

* Add demo tab showcasing ItemSpacing and LineSpacing

Co-authored-by: rabbitism <14807942+rabbitism@users.noreply.github.com>

* Add additional test for ItemSpacing affecting line wrapping

Co-authored-by: rabbitism <14807942+rabbitism@users.noreply.github.com>

* feat: add bindings for IsFillHorizontal and IsFillVertical in ElasticWrapPanelDemo

* Fix measure/arrange mismatch by tracking spacing in UVCollection

Co-authored-by: rabbitism <14807942+rabbitism@users.noreply.github.com>

* feat: add ItemSpacing & LineSpacing FormItems.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: rabbitism <14807942+rabbitism@users.noreply.github.com>
Co-authored-by: Dong Bin <popmessiah@hotmail.com>
Co-authored-by: Zhang Dian <54255897+zdpcdt@users.noreply.github.com>
This commit is contained in:
Copilot
2025-12-16 20:39:50 +08:00
committed by GitHub
parent 6f7db1c20c
commit e54474b0f9
4 changed files with 263 additions and 15 deletions

View File

@@ -64,6 +64,22 @@
Minimum="0" Minimum="0"
Value="{Binding ItemHeight}" /> Value="{Binding ItemHeight}" />
</u:FormItem> </u:FormItem>
<u:FormItem Label="ItemSpacing">
<u:NumericDoubleUpDown
AllowDrag="True"
Step="1"
Maximum="100"
Minimum="-10"
Value="{Binding ItemSpacing}" />
</u:FormItem>
<u:FormItem Label="LineSpacing">
<u:NumericDoubleUpDown
AllowDrag="True"
Step="1"
Maximum="100"
Minimum="-10"
Value="{Binding LineSpacing}" />
</u:FormItem>
</u:FormGroup> </u:FormGroup>
<u:FormGroup Header="FixToRB Extension" IsEnabled="{Binding #FixToRBTabItem.IsSelected}"> <u:FormGroup Header="FixToRB Extension" IsEnabled="{Binding #FixToRBTabItem.IsSelected}">
<u:FormItem> <u:FormItem>
@@ -108,6 +124,8 @@
IsFillVertical="{Binding IsFillVertical}" IsFillVertical="{Binding IsFillVertical}"
ItemHeight="{Binding ItemHeight}" ItemHeight="{Binding ItemHeight}"
ItemWidth="{Binding ItemWidth}" ItemWidth="{Binding ItemWidth}"
ItemSpacing="{Binding ItemSpacing}"
LineSpacing="{Binding LineSpacing}"
Orientation="{Binding SelectedOrientation}"> Orientation="{Binding SelectedOrientation}">
<Border Background="{DynamicResource SemiRed5Color}" /> <Border Background="{DynamicResource SemiRed5Color}" />
<Border Background="{DynamicResource SemiPink5Color}" /> <Border Background="{DynamicResource SemiPink5Color}" />
@@ -134,6 +152,8 @@
IsFillVertical="{Binding IsFillVertical}" IsFillVertical="{Binding IsFillVertical}"
ItemHeight="{Binding ItemHeight}" ItemHeight="{Binding ItemHeight}"
ItemWidth="{Binding ItemWidth}" ItemWidth="{Binding ItemWidth}"
ItemSpacing="{Binding ItemSpacing}"
LineSpacing="{Binding LineSpacing}"
Orientation="{Binding SelectedOrientation}"> Orientation="{Binding SelectedOrientation}">
<Border Background="{DynamicResource SemiRed5Color}" /> <Border Background="{DynamicResource SemiRed5Color}" />
<Border Background="{DynamicResource SemiPink5Color}" /> <Border Background="{DynamicResource SemiPink5Color}" />
@@ -165,6 +185,8 @@
IsFillVertical="{Binding IsFillVertical}" IsFillVertical="{Binding IsFillVertical}"
ItemHeight="{Binding ItemHeight}" ItemHeight="{Binding ItemHeight}"
ItemWidth="{Binding ItemWidth}" ItemWidth="{Binding ItemWidth}"
ItemSpacing="{Binding ItemSpacing}"
LineSpacing="{Binding LineSpacing}"
Orientation="{Binding SelectedOrientation}"> Orientation="{Binding SelectedOrientation}">
<Border Background="{DynamicResource SemiRed5Color}" /> <Border Background="{DynamicResource SemiRed5Color}" />
<Border Background="{DynamicResource SemiPink5Color}" /> <Border Background="{DynamicResource SemiPink5Color}" />
@@ -200,6 +222,8 @@
<u:Divider HorizontalContentAlignment="Left" Content="WrapPanel" /> <u:Divider HorizontalContentAlignment="Left" Content="WrapPanel" />
<WrapPanel ItemHeight="{Binding ItemHeight}" <WrapPanel ItemHeight="{Binding ItemHeight}"
ItemWidth="{Binding ItemWidth}" ItemWidth="{Binding ItemWidth}"
ItemSpacing="{Binding ItemSpacing}"
LineSpacing="{Binding LineSpacing}"
Orientation="{Binding SelectedOrientation}"> Orientation="{Binding SelectedOrientation}">
<Border Background="{DynamicResource SemiRed5Color}" /> <Border Background="{DynamicResource SemiRed5Color}" />
<Border Background="{DynamicResource SemiPink5Color}" /> <Border Background="{DynamicResource SemiPink5Color}" />
@@ -223,6 +247,8 @@
IsFillVertical="{Binding IsFillVertical}" IsFillVertical="{Binding IsFillVertical}"
ItemHeight="{Binding ItemHeight}" ItemHeight="{Binding ItemHeight}"
ItemWidth="{Binding ItemWidth}" ItemWidth="{Binding ItemWidth}"
ItemSpacing="{Binding ItemSpacing}"
LineSpacing="{Binding LineSpacing}"
Orientation="{Binding SelectedOrientation}"> Orientation="{Binding SelectedOrientation}">
<Border Background="{DynamicResource SemiRed5Color}" /> <Border Background="{DynamicResource SemiRed5Color}" />
<Border Background="{DynamicResource SemiPink5Color}" /> <Border Background="{DynamicResource SemiPink5Color}" />
@@ -249,6 +275,8 @@
<u:Divider HorizontalContentAlignment="Left" Content="WrapPanel" /> <u:Divider HorizontalContentAlignment="Left" Content="WrapPanel" />
<WrapPanel ItemHeight="{Binding ItemHeight}" <WrapPanel ItemHeight="{Binding ItemHeight}"
ItemWidth="{Binding ItemWidth}" ItemWidth="{Binding ItemWidth}"
ItemSpacing="{Binding ItemSpacing}"
LineSpacing="{Binding LineSpacing}"
Orientation="{Binding SelectedOrientation}"> Orientation="{Binding SelectedOrientation}">
<Border Background="{DynamicResource SemiRed5Color}" /> <Border Background="{DynamicResource SemiRed5Color}" />
<Border Background="{DynamicResource SemiPink5Color}" /> <Border Background="{DynamicResource SemiPink5Color}" />
@@ -285,6 +313,8 @@
IsFillVertical="{Binding IsFillVertical}" IsFillVertical="{Binding IsFillVertical}"
ItemHeight="{Binding ItemHeight}" ItemHeight="{Binding ItemHeight}"
ItemWidth="{Binding ItemWidth}" ItemWidth="{Binding ItemWidth}"
ItemSpacing="{Binding ItemSpacing}"
LineSpacing="{Binding LineSpacing}"
Orientation="{Binding SelectedOrientation}"> Orientation="{Binding SelectedOrientation}">
<Border Background="{DynamicResource SemiRed5Color}" /> <Border Background="{DynamicResource SemiRed5Color}" />
<Border Background="{DynamicResource SemiPink5Color}" /> <Border Background="{DynamicResource SemiPink5Color}" />

View File

@@ -14,6 +14,8 @@ public partial class ElasticWrapPanelDemoViewModel : ObservableObject
[ObservableProperty] private bool _isFillVertical; [ObservableProperty] private bool _isFillVertical;
[ObservableProperty] private double _itemWidth = 40d; [ObservableProperty] private double _itemWidth = 40d;
[ObservableProperty] private double _itemHeight = 40d; [ObservableProperty] private double _itemHeight = 40d;
[ObservableProperty] private double _itemSpacing;
[ObservableProperty] private double _lineSpacing;
[ObservableProperty] private bool _autoWidth = true; [ObservableProperty] private bool _autoWidth = true;
[ObservableProperty] private bool _autoHeight = true; [ObservableProperty] private bool _autoHeight = true;

View File

@@ -12,8 +12,8 @@ public class ElasticWrapPanel : WrapPanel
{ {
static ElasticWrapPanel() static ElasticWrapPanel()
{ {
AffectsMeasure<ElasticWrapPanel>(IsFillHorizontalProperty, IsFillVerticalProperty); AffectsMeasure<ElasticWrapPanel>(IsFillHorizontalProperty, IsFillVerticalProperty, ItemSpacingProperty, LineSpacingProperty);
AffectsArrange<ElasticWrapPanel>(IsFillHorizontalProperty, IsFillVerticalProperty); AffectsArrange<ElasticWrapPanel>(IsFillHorizontalProperty, IsFillVerticalProperty, ItemSpacingProperty, LineSpacingProperty);
} }
#region AttachedProperty #region AttachedProperty
@@ -78,6 +78,8 @@ public class ElasticWrapPanel : WrapPanel
double itemHeight = ItemHeight; double itemHeight = ItemHeight;
var orientation = Orientation; var orientation = Orientation;
var children = Children; var children = Children;
double itemSpacing = ItemSpacing;
double lineSpacing = LineSpacing;
// Determine the space required for items in the same row/column based on horizontal/vertical arrangement // Determine the space required for items in the same row/column based on horizontal/vertical arrangement
var curLineSize = new UVSize(orientation); var curLineSize = new UVSize(orientation);
@@ -111,6 +113,8 @@ public class ElasticWrapPanel : WrapPanel
itemWidthSet ? itemWidth : 0, itemWidthSet ? itemWidth : 0,
itemHeightSet ? itemHeight : 0); itemHeightSet ? itemHeight : 0);
bool isFirstItemInLine = true;
foreach (var child in children) foreach (var child in children)
{ {
UVSize sz; UVSize sz;
@@ -138,21 +142,38 @@ public class ElasticWrapPanel : WrapPanel
sz.V = itemSetSize.V; sz.V = itemSetSize.V;
} }
if (MathHelpers.GreaterThan(curLineSize.U + sz.U, uvConstraint.U)) double itemUWithSpacing = isFirstItemInLine ? sz.U : sz.U + itemSpacing;
if (MathHelpers.GreaterThan(curLineSize.U + itemUWithSpacing, uvConstraint.U))
{ {
panelSize.U = Max(curLineSize.U, panelSize.U); panelSize.U = Max(curLineSize.U, panelSize.U);
if (panelSize.V > 0)
{
panelSize.V += lineSpacing;
}
panelSize.V += curLineSize.V; panelSize.V += curLineSize.V;
curLineSize = sz; curLineSize = sz;
isFirstItemInLine = false;
} }
else else
{ {
if (!isFirstItemInLine)
{
curLineSize.U += itemSpacing;
}
curLineSize.U += sz.U; curLineSize.U += sz.U;
curLineSize.V = Max(sz.V, curLineSize.V); curLineSize.V = Max(sz.V, curLineSize.V);
panelSize.U = Max(curLineSize.U, panelSize.U); panelSize.U = Max(curLineSize.U, panelSize.U);
if (panelSize.V > 0)
{
panelSize.V += lineSpacing;
}
panelSize.V += curLineSize.V; panelSize.V += curLineSize.V;
isFirstItemInLine = false;
} }
curLineSize = new UVSize(orientation); curLineSize = new UVSize(orientation);
isFirstItemInLine = true;
} }
else else
{ {
@@ -164,23 +185,40 @@ public class ElasticWrapPanel : WrapPanel
itemWidthSet ? itemWidth : child.DesiredSize.Width, itemWidthSet ? itemWidth : child.DesiredSize.Width,
itemHeightSet ? itemHeight : child.DesiredSize.Height); itemHeightSet ? itemHeight : child.DesiredSize.Height);
if (MathHelpers.GreaterThan(curLineSize.U + sz.U, uvConstraint.U)) // Need to switch to another line double itemUWithSpacing = isFirstItemInLine ? sz.U : sz.U + itemSpacing;
if (MathHelpers.GreaterThan(curLineSize.U + itemUWithSpacing, uvConstraint.U)) // Need to switch to another line
{ {
panelSize.U = Max(curLineSize.U, panelSize.U); panelSize.U = Max(curLineSize.U, panelSize.U);
if (panelSize.V > 0)
{
panelSize.V += lineSpacing;
}
panelSize.V += curLineSize.V; panelSize.V += curLineSize.V;
curLineSize = sz; curLineSize = sz;
isFirstItemInLine = false;
if (MathHelpers.GreaterThan(sz.U, uvConstraint.U)) // The element is wider than the constraint - give it a separate line if (MathHelpers.GreaterThan(sz.U, uvConstraint.U)) // The element is wider than the constraint - give it a separate line
{ {
panelSize.U = Max(sz.U, panelSize.U); panelSize.U = Max(sz.U, panelSize.U);
if (panelSize.V > 0)
{
panelSize.V += lineSpacing;
}
panelSize.V += sz.V; panelSize.V += sz.V;
curLineSize = new UVSize(orientation); curLineSize = new UVSize(orientation);
isFirstItemInLine = true;
} }
} }
else // Continue to accumulate a line else // Continue to accumulate a line
{ {
if (!isFirstItemInLine)
{
curLineSize.U += itemSpacing;
}
curLineSize.U += sz.U; curLineSize.U += sz.U;
curLineSize.V = Max(sz.V, curLineSize.V); curLineSize.V = Max(sz.V, curLineSize.V);
isFirstItemInLine = false;
} }
} }
} }
@@ -197,6 +235,8 @@ public class ElasticWrapPanel : WrapPanel
{ {
bool itemWidthSet = !double.IsNaN(ItemWidth); bool itemWidthSet = !double.IsNaN(ItemWidth);
bool itemHeightSet = !double.IsNaN(ItemHeight); bool itemHeightSet = !double.IsNaN(ItemHeight);
double itemSpacing = ItemSpacing;
double lineSpacing = LineSpacing;
// This is the size for non-space measurement // This is the size for non-space measurement
UVSize itemSetSize = new UVSize(Orientation, UVSize itemSetSize = new UVSize(Orientation,
@@ -212,7 +252,7 @@ public class ElasticWrapPanel : WrapPanel
#region Get the collection of elements in the same direction #region Get the collection of elements in the same direction
// Current collection of elements in a row/column // Current collection of elements in a row/column
UVCollection curLineUIs = new UVCollection(Orientation, itemSetSize); UVCollection curLineUIs = new UVCollection(Orientation, itemSetSize, itemSpacing);
// Iterate over the child elements // Iterate over the child elements
var children = Children; var children = Children;
@@ -242,14 +282,16 @@ public class ElasticWrapPanel : WrapPanel
sz.V = itemSetSize.V; sz.V = itemSetSize.V;
} }
if (MathHelpers.GreaterThan(curLineUIs.TotalU + sz.U, uvFinalSize.U)) // Account for spacing before this item if it's not the first
double spacingBeforeItem = curLineUIs.Count > 0 ? itemSpacing : 0;
if (MathHelpers.GreaterThan(curLineUIs.TotalU + spacingBeforeItem + sz.U, uvFinalSize.U))
{ {
if (curLineUIs.Count > 0) if (curLineUIs.Count > 0)
{ {
lineUVCollection.Add(curLineUIs); lineUVCollection.Add(curLineUIs);
} }
curLineUIs = new UVCollection(Orientation, itemSetSize); curLineUIs = new UVCollection(Orientation, itemSetSize, itemSpacing);
curLineUIs.Add(child, sz, Convert.ToInt32(lengthCount)); curLineUIs.Add(child, sz, Convert.ToInt32(lengthCount));
} }
else else
@@ -258,7 +300,7 @@ public class ElasticWrapPanel : WrapPanel
} }
lineUVCollection.Add(curLineUIs); lineUVCollection.Add(curLineUIs);
curLineUIs = new UVCollection(Orientation, itemSetSize); curLineUIs = new UVCollection(Orientation, itemSetSize, itemSpacing);
} }
else else
{ {
@@ -266,19 +308,21 @@ public class ElasticWrapPanel : WrapPanel
itemWidthSet ? ItemWidth : child.DesiredSize.Width, itemWidthSet ? ItemWidth : child.DesiredSize.Width,
itemHeightSet ? ItemHeight : child.DesiredSize.Height); itemHeightSet ? ItemHeight : child.DesiredSize.Height);
if (MathHelpers.GreaterThan(curLineUIs.TotalU + sz.U, uvFinalSize.U)) // Need to switch to another line // Account for spacing before this item if it's not the first
double spacingBeforeItem = curLineUIs.Count > 0 ? itemSpacing : 0;
if (MathHelpers.GreaterThan(curLineUIs.TotalU + spacingBeforeItem + sz.U, uvFinalSize.U)) // Need to switch to another line
{ {
if (curLineUIs.Count > 0) if (curLineUIs.Count > 0)
{ {
lineUVCollection.Add(curLineUIs); lineUVCollection.Add(curLineUIs);
} }
curLineUIs = new UVCollection(Orientation, itemSetSize); curLineUIs = new UVCollection(Orientation, itemSetSize, itemSpacing);
curLineUIs.Add(child, sz); curLineUIs.Add(child, sz);
if (MathHelpers.GreaterThan(sz.U, uvFinalSize.U)) if (MathHelpers.GreaterThan(sz.U, uvFinalSize.U))
{ {
lineUVCollection.Add(curLineUIs); lineUVCollection.Add(curLineUIs);
curLineUIs = new UVCollection(Orientation, itemSetSize); curLineUIs = new UVCollection(Orientation, itemSetSize, itemSpacing);
} }
} }
else else
@@ -332,7 +376,8 @@ public class ElasticWrapPanel : WrapPanel
} }
maxElementCount = Max(sum, maxElementCount); maxElementCount = Max(sum, maxElementCount);
} }
adaptULength = (uvFinalSize.U - maxElementCount * itemSetSize.U) / maxElementCount; double totalItemSpacing = maxElementCount > 1 ? (maxElementCount - 1) * itemSpacing : 0;
adaptULength = (uvFinalSize.U - maxElementCount * itemSetSize.U - totalItemSpacing) / maxElementCount;
adaptULength = Max(adaptULength, 0); adaptULength = Max(adaptULength, 0);
} }
} }
@@ -342,16 +387,19 @@ public class ElasticWrapPanel : WrapPanel
if (itemSetSize.V > 0) if (itemSetSize.V > 0)
{ {
isAdaptV = true; isAdaptV = true;
adaptVLength = uvFinalSize.V / lineUVCollection.Count; double totalLineSpacing = lineUVCollection.Count > 1 ? (lineUVCollection.Count - 1) * lineSpacing : 0;
adaptVLength = (uvFinalSize.V - totalLineSpacing) / lineUVCollection.Count;
} }
} }
bool isHorizontal = Orientation == Orientation.Horizontal; bool isHorizontal = Orientation == Orientation.Horizontal;
int lineIndex = 0;
foreach (var uvCollection in lineUVCollection) foreach (var uvCollection in lineUVCollection)
{ {
double u = 0; double u = 0;
var lineUIEles = uvCollection.UICollection.Keys.ToList(); var lineUIEles = uvCollection.UICollection.Keys.ToList();
double linevV = isAdaptV ? adaptVLength : uvCollection.LineV; double linevV = isAdaptV ? adaptVLength : uvCollection.LineV;
int itemIndex = 0;
foreach (var child in lineUIEles) foreach (var child in lineUIEles)
{ {
UVLengthSize childSize = uvCollection.UICollection[child]; UVLengthSize childSize = uvCollection.UICollection[child];
@@ -384,9 +432,19 @@ public class ElasticWrapPanel : WrapPanel
} }
u += layoutSlotU; u += layoutSlotU;
if (itemIndex < lineUIEles.Count - 1)
{
u += itemSpacing;
}
itemIndex++;
} }
accumulatedV += linevV; accumulatedV += linevV;
if (lineIndex < lineUVCollection.Count - 1)
{
accumulatedV += lineSpacing;
}
lineIndex++;
lineUIEles.Clear(); lineUIEles.Clear();
} }
} }
@@ -462,15 +520,26 @@ public class ElasticWrapPanel : WrapPanel
private UVSize LineDesireUVSize; private UVSize LineDesireUVSize;
private UVSize ItemSetSize; private UVSize ItemSetSize;
private double ItemSpacing;
public UVCollection(Orientation orientation, UVSize itemSetSize) public UVCollection(Orientation orientation, UVSize itemSetSize, double itemSpacing = 0)
{ {
UICollection = new Dictionary<Control, UVLengthSize>(); UICollection = new Dictionary<Control, UVLengthSize>();
LineDesireUVSize = new UVSize(orientation); LineDesireUVSize = new UVSize(orientation);
ItemSetSize = itemSetSize; ItemSetSize = itemSetSize;
ItemSpacing = itemSpacing;
} }
public double TotalU => LineDesireUVSize.U; public double TotalU
{
get
{
// TotalU includes spacing between items (not before first or after last)
double spacingTotal = UICollection.Count > 1 ? (UICollection.Count - 1) * ItemSpacing : 0;
return LineDesireUVSize.U + spacingTotal;
}
}
public double LineV => LineDesireUVSize.V; public double LineV => LineDesireUVSize.V;

View File

@@ -69,4 +69,151 @@ public class Tests
window.Show(); window.Show();
Assert.Equal(2, panel.LineCount); Assert.Equal(2, panel.LineCount);
} }
[AvaloniaFact]
public void ItemSpacing_Applied_Correctly()
{
var window = new Window() { };
var panel = new ElasticWrapPanel
{
Width = 400,
Height = 200,
Orientation = Orientation.Horizontal,
ItemSpacing = 10,
};
// Add 3 rectangles of 100x100 with 10px spacing
// Total width should be: 100 + 10 + 100 + 10 + 100 = 320
for (int i = 0; i < 3; i++)
{
var rect = new Rectangle
{
Width = 100,
Height = 100,
};
panel.Children.Add(rect);
}
window.Content = panel;
window.Show();
// All 3 should fit on one line
Assert.Equal(1, panel.LineCount);
// Check that the desired size accounts for spacing
Assert.True(panel.DesiredSize.Width >= 320);
}
[AvaloniaFact]
public void LineSpacing_Applied_Correctly()
{
var window = new Window() { };
var panel = new ElasticWrapPanel
{
Width = 200,
Height = 400,
Orientation = Orientation.Horizontal,
LineSpacing = 20,
};
// Add 4 rectangles of 100x100, should wrap to 2 lines
for (int i = 0; i < 4; i++)
{
var rect = new Rectangle
{
Width = 100,
Height = 100,
};
panel.Children.Add(rect);
}
window.Content = panel;
window.Show();
// Should have 2 lines
Assert.Equal(2, panel.LineCount);
// Total height should be: 100 + 20 + 100 = 220
Assert.True(panel.DesiredSize.Height >= 220);
}
[AvaloniaFact]
public void ItemSpacing_And_LineSpacing_Together()
{
var window = new Window() { };
var panel = new ElasticWrapPanel
{
Width = 250,
Height = 400,
Orientation = Orientation.Horizontal,
ItemSpacing = 10,
LineSpacing = 20,
};
// Add 4 rectangles of 100x100
// With ItemSpacing=10, two items per line need 100 + 10 + 100 = 210 width
// With LineSpacing=20, two lines need 100 + 20 + 100 = 220 height
for (int i = 0; i < 4; i++)
{
var rect = new Rectangle
{
Width = 100,
Height = 100,
};
panel.Children.Add(rect);
}
window.Content = panel;
window.Show();
// Should have 2 lines
Assert.Equal(2, panel.LineCount);
// Check dimensions include spacing
Assert.True(panel.DesiredSize.Width >= 210);
Assert.True(panel.DesiredSize.Height >= 220);
}
[AvaloniaFact]
public void ItemSpacing_Does_Not_Affect_LineCount()
{
var window = new Window() { };
// Panel without spacing - should fit 2 items per line (200 width / 100 per item = 2)
var panel1 = new ElasticWrapPanel
{
Width = 200,
Height = 400,
Orientation = Orientation.Horizontal,
ItemSpacing = 0,
};
for (int i = 0; i < 4; i++)
{
panel1.Children.Add(new Rectangle { Width = 100, Height = 100 });
}
// Panel with spacing - items with spacing should fit fewer per line
// 100 + 10 + 100 = 210 > 200, so only 1 item per line
var panel2 = new ElasticWrapPanel
{
Width = 200,
Height = 400,
Orientation = Orientation.Horizontal,
ItemSpacing = 10,
};
for (int i = 0; i < 4; i++)
{
panel2.Children.Add(new Rectangle { Width = 100, Height = 100 });
}
window.Content = panel1;
window.Show();
Assert.Equal(2, panel1.LineCount); // 2 items per line, 4 items total = 2 lines
window.Content = panel2;
window.UpdateLayout();
Assert.Equal(4, panel2.LineCount); // 1 item per line, 4 items total = 4 lines
}
} }