diff --git a/components/Primitives/src/WrapLayout/UvBounds.cs b/components/Primitives/src/WrapLayout/UvBounds.cs
index 782f605c..e2a5ad44 100644
--- a/components/Primitives/src/WrapLayout/UvBounds.cs
+++ b/components/Primitives/src/WrapLayout/UvBounds.cs
@@ -8,7 +8,7 @@ internal struct UvBounds
{
public UvBounds(Orientation orientation, Rect rect)
{
- if (orientation == Orientation.Horizontal)
+ if (orientation is Orientation.Horizontal)
{
UMin = rect.Left;
UMax = rect.Right;
diff --git a/components/Primitives/src/WrapLayout/UvMeasure.cs b/components/Primitives/src/WrapLayout/UvMeasure.cs
index 549e1113..3e89cfed 100644
--- a/components/Primitives/src/WrapLayout/UvMeasure.cs
+++ b/components/Primitives/src/WrapLayout/UvMeasure.cs
@@ -7,34 +7,52 @@ namespace CommunityToolkit.WinUI.Controls;
[DebuggerDisplay("U = {U} V = {V}")]
internal struct UvMeasure
{
- internal static readonly UvMeasure Zero = default(UvMeasure);
-
internal double U { get; set; }
internal double V { get; set; }
- public UvMeasure(Orientation orientation, double width, double height)
+ public UvMeasure(Orientation orientation, Size size)
{
- if (orientation == Orientation.Horizontal)
+ if (orientation is Orientation.Horizontal)
{
- U = width;
- V = height;
+ U = size.Width;
+ V = size.Height;
}
else
{
- U = height;
- V = width;
+ U = size.Height;
+ V = size.Width;
}
}
+ public Point GetPoint(Orientation orientation)
+ {
+ return orientation is Orientation.Horizontal ? new Point(U, V) : new Point(V, U);
+ }
+
+ public Size GetSize(Orientation orientation)
+ {
+ return orientation is Orientation.Horizontal ? new Size(U, V) : new Size(V, U);
+ }
+
+ public static bool operator ==(UvMeasure measure1, UvMeasure measure2)
+ {
+ return measure1.U == measure2.U && measure1.V == measure2.V;
+ }
+
+ public static bool operator !=(UvMeasure measure1, UvMeasure measure2)
+ {
+ return !(measure1 == measure2);
+ }
+
public override bool Equals(object? obj)
{
- if (obj is UvMeasure measure)
- {
- return (measure.U == U) && (measure.V == V);
- }
+ return obj is UvMeasure measure && this == measure;
+ }
- return false;
+ public bool Equals(UvMeasure value)
+ {
+ return this == value;
}
public override int GetHashCode()
diff --git a/components/Primitives/src/WrapLayout/WrapItem.cs b/components/Primitives/src/WrapLayout/WrapItem.cs
index af311002..10d10788 100644
--- a/components/Primitives/src/WrapLayout/WrapItem.cs
+++ b/components/Primitives/src/WrapLayout/WrapItem.cs
@@ -8,7 +8,7 @@ internal class WrapItem
{
public WrapItem(int index)
{
- this.Index = index;
+ Index = index;
}
public int Index { get; }
diff --git a/components/Primitives/src/WrapLayout/WrapLayout.cs b/components/Primitives/src/WrapLayout/WrapLayout.cs
index a1108517..7bc99a0f 100644
--- a/components/Primitives/src/WrapLayout/WrapLayout.cs
+++ b/components/Primitives/src/WrapLayout/WrapLayout.cs
@@ -20,8 +20,8 @@ public class WrapLayout : VirtualizingLayout
///
public double HorizontalSpacing
{
- get { return (double)GetValue(HorizontalSpacingProperty); }
- set { SetValue(HorizontalSpacingProperty, value); }
+ get => (double)GetValue(HorizontalSpacingProperty);
+ set => SetValue(HorizontalSpacingProperty, value);
}
///
@@ -40,8 +40,8 @@ public double HorizontalSpacing
///
public double VerticalSpacing
{
- get { return (double)GetValue(VerticalSpacingProperty); }
- set { SetValue(VerticalSpacingProperty, value); }
+ get => (double)GetValue(VerticalSpacingProperty);
+ set => SetValue(VerticalSpacingProperty, value);
}
///
@@ -61,8 +61,8 @@ public double VerticalSpacing
///
public Orientation Orientation
{
- get { return (Orientation)GetValue(OrientationProperty); }
- set { SetValue(OrientationProperty, value); }
+ get => (Orientation)GetValue(OrientationProperty);
+ set => SetValue(OrientationProperty, value);
}
///
@@ -87,8 +87,7 @@ private static void LayoutPropertyChanged(DependencyObject d, DependencyProperty
///
protected override void InitializeForContextCore(VirtualizingLayoutContext context)
{
- var state = new WrapLayoutState(context);
- context.LayoutState = state;
+ context.LayoutState = new WrapLayoutState(context);
base.InitializeForContextCore(context);
}
@@ -110,7 +109,7 @@ protected override void OnItemsChangedCore(VirtualizingLayoutContext context, ob
state.RemoveFromIndex(args.NewStartingIndex);
break;
case NotifyCollectionChangedAction.Move:
- int minIndex = Math.Min(args.NewStartingIndex, args.OldStartingIndex);
+ var minIndex = Math.Min(args.NewStartingIndex, args.OldStartingIndex);
state.RemoveFromIndex(minIndex);
state.RecycleElementAt(args.OldStartingIndex);
@@ -134,11 +133,8 @@ protected override void OnItemsChangedCore(VirtualizingLayoutContext context, ob
///
protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize)
{
- var totalMeasure = UvMeasure.Zero;
- var parentMeasure = new UvMeasure(Orientation, availableSize.Width, availableSize.Height);
- var spacingMeasure = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing);
- var realizationBounds = new UvBounds(Orientation, context.RealizationRect);
- var position = UvMeasure.Zero;
+ var parentMeasure = new UvMeasure(Orientation, availableSize);
+ var spacingMeasure = new UvMeasure(Orientation, new Size(HorizontalSpacing, VerticalSpacing));
var state = (WrapLayoutState)context.LayoutState;
if (state.Orientation != Orientation)
@@ -146,38 +142,31 @@ protected override Size MeasureOverride(VirtualizingLayoutContext context, Size
state.SetOrientation(Orientation);
}
- if (spacingMeasure.Equals(state.Spacing) == false)
+ if (spacingMeasure != state.Spacing || state.AvailableU != parentMeasure.U)
{
state.ClearPositions();
state.Spacing = spacingMeasure;
- }
-
- if (state.AvailableU != parentMeasure.U)
- {
- state.ClearPositions();
state.AvailableU = parentMeasure.U;
}
double currentV = 0;
- for (int i = 0; i < context.ItemCount; i++)
+ var realizationBounds = new UvBounds(Orientation, context.RealizationRect);
+ var position = new UvMeasure();
+ for (var i = 0; i < context.ItemCount; ++i)
{
- bool measured = false;
- WrapItem item = state.GetItemAt(i);
- if (item.Measure == null)
+ var measured = false;
+ var item = state.GetItemAt(i);
+ if (item.Measure is null)
{
item.Element = context.GetOrCreateElementAt(i);
item.Element.Measure(availableSize);
- item.Measure = new UvMeasure(Orientation, item.Element.DesiredSize.Width, item.Element.DesiredSize.Height);
+ item.Measure = new UvMeasure(Orientation, item.Element.DesiredSize);
measured = true;
}
- UvMeasure currentMeasure = item.Measure.Value;
- if (currentMeasure.U == 0)
- {
- continue; // ignore collapsed items
- }
+ var currentMeasure = item.Measure.Value;
- if (item.Position == null)
+ if (item.Position is null)
{
if (parentMeasure.U < position.U + currentMeasure.U)
{
@@ -192,20 +181,22 @@ protected override Size MeasureOverride(VirtualizingLayoutContext context, Size
position = item.Position.Value;
- double vEnd = position.V + currentMeasure.V;
+ var vEnd = position.V + currentMeasure.V;
if (vEnd < realizationBounds.VMin)
{
// Item is "above" the bounds
- if (item.Element != null)
+ if (item.Element is not null)
{
context.RecycleElement(item.Element);
item.Element = null;
}
+
+ continue;
}
else if (position.V > realizationBounds.VMax)
{
// Item is "below" the bounds.
- if (item.Element != null)
+ if (item.Element is not null)
{
context.RecycleElement(item.Element);
item.Element = null;
@@ -214,14 +205,14 @@ protected override Size MeasureOverride(VirtualizingLayoutContext context, Size
// We don't need to measure anything below the bounds
break;
}
- else if (measured == false)
+ else if (!measured)
{
// Always measure elements that are within the bounds
item.Element = context.GetOrCreateElementAt(i);
item.Element.Measure(availableSize);
- currentMeasure = new UvMeasure(Orientation, item.Element.DesiredSize.Width, item.Element.DesiredSize.Height);
- if (currentMeasure.Equals(item.Measure) == false)
+ currentMeasure = new UvMeasure(Orientation, item.Element.DesiredSize);
+ if (currentMeasure != item.Measure)
{
// this item changed size; we need to recalculate layout for everything after this
state.RemoveFromIndex(i + 1);
@@ -249,20 +240,17 @@ protected override Size MeasureOverride(VirtualizingLayoutContext context, Size
// if the last loop is (parentMeasure.U > currentMeasure.U) the currentMeasure isn't added to the total so add it here
// for the last condition it is zeros so adding it will make no difference
// this way is faster than an if condition in every loop for checking the last item
- totalMeasure.U = parentMeasure.U;
-
// Propagating an infinite size causes a crash. This can happen if the parent is scrollable and infinite in the opposite
// axis to the panel. Clearing to zero prevents the crash.
- // This is likely an incorrect use of the control by the developer, however we need stability here so setting a default that wont crash.
- if (double.IsInfinity(totalMeasure.U))
- {
- totalMeasure.U = 0.0;
- }
+ // 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.
- totalMeasure.V = state.GetHeight();
+ var totalMeasure = new UvMeasure
+ {
+ U = double.IsInfinity(parentMeasure.U) ? 0 : Math.Ceiling(parentMeasure.U),
+ V = state.GetHeight()
+ };
- totalMeasure.U = Math.Ceiling(totalMeasure.U);
- return Orientation == Orientation.Horizontal ? new Size((float)totalMeasure.U, (float)totalMeasure.V) : new Size((float)totalMeasure.V, (float)totalMeasure.U);
+ return totalMeasure.GetSize(Orientation);
}
///
@@ -270,49 +258,25 @@ protected override Size ArrangeOverride(VirtualizingLayoutContext context, Size
{
if (context.ItemCount > 0)
{
- var parentMeasure = new UvMeasure(Orientation, finalSize.Width, finalSize.Height);
- var spacingMeasure = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing);
var realizationBounds = new UvBounds(Orientation, context.RealizationRect);
var state = (WrapLayoutState)context.LayoutState;
- bool Arrange(WrapItem item, bool isLast = false)
+ bool ArrangeItem(WrapItem item)
{
- if (item.Measure.HasValue == false)
- {
- return false;
- }
-
- if (item.Position == null)
+ if (item is { Measure: null } or { Position: null })
{
return false;
}
var desiredMeasure = item.Measure.Value;
- if (desiredMeasure.U == 0)
- {
- return true; // if an item is collapsed, avoid adding the spacing
- }
- UvMeasure position = item.Position.Value;
+ var position = item.Position.Value;
- // Stretch the last item to fill the available space
- if (isLast)
- {
- desiredMeasure.U = parentMeasure.U - position.U;
- }
-
- if (((position.V + desiredMeasure.V) >= realizationBounds.VMin) && (position.V <= realizationBounds.VMax))
+ if (realizationBounds.VMin <= position.V + desiredMeasure.V && position.V <= realizationBounds.VMax)
{
// place the item
- UIElement child = context.GetOrCreateElementAt(item.Index);
- if (Orientation == Orientation.Horizontal)
- {
- child.Arrange(new Rect((float)position.U, (float)position.V, (float)desiredMeasure.U, (float)desiredMeasure.V));
- }
- else
- {
- child.Arrange(new Rect((float)position.V, (float)position.U, (float)desiredMeasure.V, (float)desiredMeasure.U));
- }
+ var child = context.GetOrCreateElementAt(item.Index);
+ child.Arrange(new Rect(position.GetPoint(Orientation), desiredMeasure.GetSize(Orientation)));
}
else if (position.V > realizationBounds.VMax)
{
@@ -322,10 +286,9 @@ bool Arrange(WrapItem item, bool isLast = false)
return true;
}
- for (var i = 0; i < context.ItemCount; i++)
+ for (var i = 0; i < context.ItemCount; ++i)
{
- bool continueArranging = Arrange(state.GetItemAt(i));
- if (continueArranging == false)
+ if (!ArrangeItem(state.GetItemAt(i)))
{
break;
}
diff --git a/components/Primitives/src/WrapLayout/WrapLayoutState.cs b/components/Primitives/src/WrapLayout/WrapLayoutState.cs
index 6c7d35b5..80d98e92 100644
--- a/components/Primitives/src/WrapLayout/WrapLayoutState.cs
+++ b/components/Primitives/src/WrapLayout/WrapLayoutState.cs
@@ -8,12 +8,12 @@ namespace CommunityToolkit.WinUI.Controls;
internal class WrapLayoutState
{
- private List _items = new List();
- private VirtualizingLayoutContext _context;
+ private readonly List _items = new();
+ private readonly VirtualizingLayoutContext _context;
public WrapLayoutState(VirtualizingLayoutContext context)
{
- this._context = context;
+ _context = context;
}
public Orientation Orientation { get; private set; }
@@ -35,7 +35,7 @@ internal WrapItem GetItemAt(int index)
}
else
{
- WrapItem item = new WrapItem(index);
+ var item = new WrapItem(index);
_items.Add(item);
return item;
}
@@ -54,7 +54,7 @@ internal void RemoveFromIndex(int index)
return;
}
- int numToRemove = _items.Count - index;
+ var numToRemove = _items.Count - index;
_items.RemoveRange(index, numToRemove);
}
@@ -62,10 +62,8 @@ internal void SetOrientation(Orientation orientation)
{
foreach (var item in _items.Where(i => i.Measure.HasValue))
{
- UvMeasure measure = item.Measure!.Value;
- double v = measure.V;
- measure.V = measure.U;
- measure.U = v;
+ var measure = item.Measure!.Value;
+ (measure.V, measure.U) = (measure.U, measure.V);
item.Measure = measure;
item.Position = null;
}
@@ -84,58 +82,39 @@ internal void ClearPositions()
internal double GetHeight()
{
- if (_items.Count == 0)
+ if (_items.Count is 0)
{
return 0;
}
- bool calculateAverage = true;
- if ((_items.Count == _context.ItemCount) && _items[_items.Count - 1].Position.HasValue)
- {
- calculateAverage = false;
- }
-
UvMeasure? lastPosition = null;
double maxV = 0;
- int itemCount = _items.Count;
- for (int i = _items.Count - 1; i >= 0; i--)
+ for (var i = _items.Count - 1; i >= 0; --i)
{
var item = _items[i];
- if (item.Position == null)
+ if (item.Position is null || item.Measure is null)
{
- itemCount--;
continue;
}
- if (lastPosition != null)
+ if (lastPosition is not null && lastPosition.Value.V > item.Position.Value.V)
{
- if (lastPosition.Value.V > item.Position.Value.V)
- {
- // This is a row above the last item. Exit and calculate the average
- break;
- }
+ // This is a row above the last item.
+ break;
}
lastPosition = item.Position;
- maxV = Math.Max(maxV, item.Measure!.Value.V);
+ maxV = Math.Max(maxV, item.Measure.Value.V);
}
- double totalHeight = lastPosition!.Value.V + maxV;
- if (calculateAverage)
- {
- return (totalHeight / itemCount) * _context.ItemCount;
- }
- else
- {
- return totalHeight;
- }
+ return lastPosition?.V + maxV ?? 0;
}
internal void RecycleElementAt(int index)
{
- UIElement element = _context.GetOrCreateElementAt(index);
+ var element = _context.GetOrCreateElementAt(index);
_context.RecycleElement(element);
}
}