简体   繁体   中英

WPF WrapPanel Dynamic Height

I have a wrap panel that will contain a variable amount of controls.

I want the orientation to be vertical (as objects within will have a fixed width but variable height).

But the issue I'm having is that when a scrollbar is present the height is inifinite so the items never wrap onto the second column. The scrollbar is necessary as there will frequently be more objects than it's possible to fit on one screen. I can stop this by setting a fixed height, but this isn't an acceptable solution as a reasonable fixed height will differ for each selection.

Essentially I'd like a WrapPanel whose height changes dynamically based on the width of the panel and the amount of items contained within.

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 changes the size of the window to the point where it can only accomodate 2 columns the height will increase:

| 1 6 |

| 2 7 |

| 3 8 | Height = 5

| 4 9 |

| 5 - |

Also, I'm not sure how feasible this is but I would ideally like the order the items horizonatally but keep the orientation vertical, so they'd be ordered:

| 1 2 3 |

| 4 5 6 |

| 7 8 9 |

Could anyone tell me how to go about getting started with this? I'm assuming it's possible with a custom implementation of the WrapPanel , but I'm slightly confused how to get started.

Thanks,

Manged to achieve what I needed 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's 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;
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM