Динамическая высота WPF WrapPanel

У меня есть панель обертки, которая будет содержать переменное количество элементов управления.

Я хочу, чтобы ориентация была вертикальной (поскольку объекты внутри будут иметь фиксированную ширину, но переменную высоту).

Но проблема, с которой я сталкиваюсь, заключается в том, что при наличии полосы прокрутки высота бесконечна, поэтому элементы никогда не переносятся во второй столбец. Полоса прокрутки необходима, так как часто будет больше объектов, чем возможно разместить на одном экране. Я могу остановить это, установив фиксированную высоту, но это неприемлемое решение, поскольку разумная фиксированная высота будет отличаться для каждого выбора.

По сути, мне нужен WrapPanel, высота которого динамически изменяется в зависимости от ширины панели и количества элементов, содержащихся внутри.

Проиллюстрировать:

Если панель достаточно широка, чтобы показать 3 столбца, она будет:

| 1 5 9 |

| 2 6 - |

| 3 7 - | Высота=4

| 4 8 - |

Но если пользователь изменит размер окна до такой степени, что оно может вместить только 2 столбца, высота увеличится:

| 1 6 |

| 2 7 |

| 3 8 | Высота = 5

| 4 9 |

| 5 - |

Кроме того, я не уверен, насколько это возможно, но в идеале я хотел бы расположить элементы горизонтально, но сохранить вертикальную ориентацию, чтобы они были упорядочены:

| 1 2 3 |

| 4 5 6 |

| 7 8 9 |

Может ли кто-нибудь сказать мне, как начать с этого? Я предполагаю, что это возможно с пользовательской реализацией WrapPanel, но я немного запутался, как начать.

Спасибо,


person RagtimeWilly    schedule 19.06.2012    source источник
comment
Я не совсем уверен, что вам нужно, но посмотрите, поможет ли это stackoverflow.com/questions/9769618/   -  person Phil    schedule 19.06.2012
comment
Возможно, это может вам помочь, WrapGridPanel: stackoverflow.com/questions/4598377/   -  person Fredrik Hedblad    schedule 19.06.2012


Ответы (1)


Мне удалось добиться того, что мне нужно, с помощью следующего кода:

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;
        }
    }
person RagtimeWilly    schedule 22.06.2012