Dynamic Height WPF WrapPanel

I have a wrapper panel that will contain a variable number of controls.

I want the orientation to be vertical (since the objects inside have a fixed width but a variable height).

But the problem I ran into is that if there is a scroll bar, the height is inifinite, so the elements never wrap in the second column. A scroll bar is necessary, as there will often be more objects than can be placed on one screen. I can stop this by setting a fixed height, but this is not an acceptable solution, since a reasonable fixed height will be different for each choice.

Essentially, I would like a WrapPanel whose height changes dynamically depending on the width of the panel and the number of elements contained inside.

To illustrate:

If the panel is wide enough to show 3 columns, it will:

| 1 5 9 |

| 2 6 - |

| 3 7 - | Height = 4

| 4 8 - |

But if the user resizes the window to the point where he can only accommodate 2 columns, the height increases:

| 1 6 |

| 2 7 |

| 3 8 | Height = 5

| 4 9 |

| 5 - |

Also, I'm not sure how possible this is, but ideally I would like to arrange the elements horizontally, but keep the orientation vertical, so they will be ordered:

| 1 2 3 |

| 4 5 6 |

| 7 8 9 |

Can someone tell me how to start with this? I assume this is possible with a custom implementation of WrapPanel , but I'm a bit confused how to get started.

Thanks,

+4
source share
1 answer

Modified to achieve what I need with the following code:

 public class InvertedWrapPanel : WrapPanel { private int itemsPerRow = 0; protected override Size MeasureOverride(Size availableSize) { if (Orientation == Orientation.Horizontal) { return base.MeasureOverride(availableSize); } else //Orientation is vertical { double w = availableSize.Width; double maxChildWidth = 0; foreach (UIElement child in Children) { //Get the current childs desired size parameters child.Measure(availableSize); //Store off the maximum child width if (child.DesiredSize.Width > maxChildWidth) maxChildWidth = child.DesiredSize.Width; } //See how many items we can fit in a row itemsPerRow = Convert.ToInt32(Math.Floor(w / maxChildWidth)); return base.MeasureOverride(availableSize); } } protected override Size ArrangeOverride(Size finalSize) { if (Orientation == Orientation.Horizontal) { return base.ArrangeOverride(finalSize); } else //Orientation is vertical { double currentX = 0; double currentY = 0; int col = 0; double lastX = 0; double lastWidth = 0; //Arrays to store differing column heights double[] lastY = new double[itemsPerRow]; double[] lastHeight = new double[itemsPerRow]; double[] colHeights = new double[itemsPerRow]; foreach (UIElement child in Children) { //If we've reached the end of a row if (col >= itemsPerRow) { col = 0; currentX = 0; //reset the x-coordinate for first column } else currentX = lastX + lastWidth; //Increase the x-coordinate //Increase the y-coordinates for the current column currentY = lastY[col] + lastHeight[col]; //Draw the element child.Arrange(new Rect(currentX, currentY, child.DesiredSize.Width, child.DesiredSize.Height)); //Store off the current child parameters lastX = currentX; lastWidth = child.DesiredSize.Width; lastY[col] = currentY; lastHeight[col] = child.DesiredSize.Height; colHeights[col] += child.DesiredSize.Height; col++; } //Set the height of the panel to the max column height. //Otherwise scroll bar will set height to infinity. double maxHeight = 0; foreach (double d in colHeights) { if (d > maxHeight) maxHeight = d; } base.Height = maxHeight; return finalSize; } } 
+3
source

All Articles