using System; using System.Linq; using System.Windows.Controls; namespace WPFluent.Layout; public class WaterfallPanel : VirtualizingPanel { public static readonly DependencyProperty ColumnsProperty = DependencyProperty.Register(nameof(Columns), typeof(int), typeof(WaterfallPanel), new PropertyMetadata(3)); public static readonly DependencyProperty SpacingProperty = DependencyProperty.Register(nameof(Spacing), typeof(double), typeof(WaterfallPanel), new PropertyMetadata(5.0)); private List columnHeights = []; protected override Size MeasureOverride(Size availableSize) { columnHeights.Clear(); var panelDesiredSize = new Size(0, 0); columnHeights = new double[Columns].ToList(); double currentX = 0; var width = availableSize.Width / Columns - (Columns * Spacing); for(var i = 0; i < InternalChildren.Count; i++) { if(InternalChildren[i] is not FrameworkElement child) continue; child.Measure(availableSize); child.Width = width; var columnIndex = i % Columns; var x = columnIndex != 0 ? currentX + Spacing : 0; var y = columnHeights[columnIndex]; if(i >= Columns) y = y + Spacing; var size = new Size(width, child.DesiredSize.Height); child.Arrange(new Rect(new Point(x, y), size)); panelDesiredSize.Width = Math.Max(panelDesiredSize.Width, x + child.DesiredSize.Width); panelDesiredSize.Height = Math.Max(panelDesiredSize.Height, y + child.DesiredSize.Height); currentX = x + size.Width; if(currentX >= Width) currentX = 0; columnHeights[columnIndex] += child.DesiredSize.Height + (i >= Columns ? Spacing : 0); } return panelDesiredSize; } public void AddChild(UIElement element) { Children.Add(element); } public int Columns { get { return (int)GetValue(ColumnsProperty); } set { SetValue(ColumnsProperty, value); } } public double Spacing { get { return (double)GetValue(SpacingProperty); } set { SetValue(SpacingProperty, value); } } }