Search code examples
wpflayoutgridwrappanel

Is there a WPF "WrapGrid" control available or an easy way to create one?


Essentially I want a wrapPanel, but I would like items to snap to a grid rather than be pressed up to the left, so I can get a nice uniform looking grid, that automatically consumes available space.

WrapPanel handles the resize part. WPF.Contrib.AutoGrid handles a nice automatic grid.

Anyone got a control that combines them?

My use case is I have a series of somewhat irregularly shaped controls. I would like them to appear in nice columns so the wrap panel should snap to the next "tabstop" when placing a control


Solution

  • Here is some code that I whipped up based on some of the other controls that are close. It does a decent job of doing the layout, although it has an issue where grand-child controls do not fill up all their available space.

      protected override Size ArrangeOverride(Size finalSize)
        {
            double rowY = 0;
            int col = 0;
            double currentRowHeight = 0;
    
    
            foreach (UIElement child in Children)
            {
                var initialSize = child.DesiredSize;
                int colspan  = (int) Math.Ceiling(initialSize.Width/ ColumnSize);
                Console.WriteLine(colspan);
                 double width = colspan * ColumnSize;
    
    
    
                if (col > 0 && (col * ColumnSize) + width > constrainedSize.Width)
                {
                    rowY += currentRowHeight;
                    col = 0;
                    currentRowHeight = 0;
                }
    
    
                var childRect = new Rect(col * ColumnSize, rowY, width, initialSize.Height);
                child.Arrange(childRect);
                currentRowHeight = Math.Max(currentRowHeight, initialSize.Height);
                col+=colspan;
            }
    
            return finalSize;
        }
    
        Size constrainedSize;
    
        protected override Size MeasureOverride(Size constraint)
        {
            constrainedSize = constraint;
            return base.MeasureOverride(constraint);
        }