固定Wrap面板WPF

13

我正在开发一个WPF窗口,用于显示一系列物品,这些物品会自动换行排列。我尝试使用WrapPanel实现此功能:

```WrapPanel```
<Grid>
    <ItemsControl>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel Orientation="Horizontal"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>

        <ItemsControl.Items>
            <Button Content="01" Height="30" Width="70"/>
            <Button Content="02" Height="35" Width="72"/>
            <Button Content="03" Height="20" Width="74"/>
            <Button Content="04" Height="25" Width="76"/>
            <Button Content="05" Height="18" Width="78"/>
            <Button Content="06" Height="50" Width="70"/>
            <Button Content="07" Height="40" Width="72"/>
            <Button Content="08" Height="55" Width="74"/>
            <Button Content="09" Height="45" Width="76"/>
            <Button Content="10" Height="25" Width="78"/>
            <Button Content="11" Height="20" Width="80"/>
            <Button Content="12" Height="30" Width="70"/>
            <Button Content="13" Height="45" Width="72"/>
            <Button Content="14" Height="30" Width="74"/>
            <Button Content="15" Height="20" Width="76"/>
            <Button Content="16" Height="25" Width="78"/>
            <Button Content="17" Height="35" Width="80"/>
            <Button Content="18" Height="50" Width="70"/>
            <Button Content="19" Height="55" Width="72"/>
            <Button Content="20" Height="45" Width="74"/>
            <Button Content="21" Height="20" Width="76"/>
            <Button Content="22" Height="60" Width="78"/>
            <Button Content="23" Height="20" Width="80"/>
            <Button Content="24" Height="25" Width="70"/>
            <Button Content="25" Height="30" Width="72"/>
        </ItemsControl.Items>
    </ItemsControl>
</Grid>

这是结果:

在此输入图像描述

实际上,这个结果对我来说令人不满意,因为如果您将WrapPanel想象成网格(行和列),您会发现没有列,但有固定大小的行。我需要制作一个没有列的WarpPanel或其他控件,看一下这个想象中的图片:

在此输入图像描述

请注意,没有行和列,这就是我想要做的。

有人有解决这个问题的想法吗?


我无法看到任何图像。 - Bathineni
2
就像Clemens已经写过的那样,您需要编写自己的面板并进行某种装箱。这篇文章可能是一个不错的起点。 - dowhilefor
2个回答

9
你可以编写自己的自定义面板类。网上有一些教程,只需谷歌搜索“wpf custom panel”。
它归结为覆盖MeasureOverrideArrangeOverride方法。
public class CustomPanel : Panel
{
    protected override Size MeasureOverride(Size availableSize)
    {
        Size panelDesiredSize = new Size();

        foreach (UIElement child in InternalChildren)
        {
            child.Measure(availableSize);

            // Use child.DesiredSize, availableSize.Width and the positions
            // and sizes of the previous children to calculate the position of
            // the current child. Then determine the resulting Panel height.
            panelDesiredSize = ...
        }

        return panelDesiredSize;
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        foreach (UIElement child in InternalChildren)
        {
            // Arrange each child according to the position calculations
            // done in MeasureOverride
            Point position = ...
            child.Arrange(new Rect(position, child.DesiredSize));
        }

        return finalSize;
    }
}

更新:下面这个简单的自定义面板可能会更多或少地满足你的需求。

public class PackPanel : Panel
{
    protected override Size MeasureOverride(Size availableSize)
    {
        foreach (UIElement child in InternalChildren)
        {
            child.Measure(availableSize);
        }

        var positions = new Point[InternalChildren.Count];
        var desiredHeight = ArrangeChildren(positions, availableSize.Width);

        return new Size(availableSize.Width, desiredHeight);
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        var positions = new Point[InternalChildren.Count];
        ArrangeChildren(positions, finalSize.Width);

        for (int i = 0; i < InternalChildren.Count; i++)
        {
            var child = InternalChildren[i];
            child.Arrange(new Rect(positions[i], child.DesiredSize));
        }

        return finalSize;
    }

    private double ArrangeChildren(Point[] positions, double availableWidth)
    {
        var lastRowStartIndex = -1;
        var lastRowEndIndex = 0;
        var currentWidth = 0d;
        var desiredHeight = 0d;

        for (int childIndex = 0; childIndex < InternalChildren.Count; childIndex++)
        {
            var child = InternalChildren[childIndex];
            var x = 0d;
            var y = 0d;

            if (currentWidth == 0d || currentWidth + child.DesiredSize.Width <= availableWidth)
            {
                x = currentWidth;
                currentWidth += child.DesiredSize.Width;
            }
            else
            {
                currentWidth = child.DesiredSize.Width;
                lastRowStartIndex = lastRowEndIndex;
                lastRowEndIndex = childIndex;
            }

            if (lastRowStartIndex >= 0)
            {
                int i = lastRowStartIndex;

                while (i < lastRowEndIndex - 1 && positions[i + 1].X < x)
                {
                    i++;
                }

                while (i < lastRowEndIndex && positions[i].X < x + child.DesiredSize.Width)
                {
                    y = Math.Max(y, positions[i].Y + InternalChildren[i].DesiredSize.Height);
                    i++;
                }
            }

            positions[childIndex] = new Point(x, y);
            desiredHeight = Math.Max(desiredHeight, y + child.DesiredSize.Height);
        }

        return desiredHeight;
    }
}

抱歉,但有数十个必须检查的情况,而且检查方式非常复杂 :( 这是制作所需面板的唯一方法吗? - Heysem Katibi
不确定您所说的“必须检查的情况”具体指什么,但是安排子元素所需的计算必须在某个地方完成。如果找不到具有所需行为的现有面板类(我怀疑您能否找到),则必须自己完成。 - Clemens

-1

你可以使用Canvas:

或者使用Grid,并根据要求设置每个按钮的边距

     <Canvas >
        <Button Content="s" Width="50" Canvas.Left="17" Canvas.Top="20" />
        <Button Canvas.Left="73" Canvas.Top="32" Content="s" Width="60" Height="42" />
        <Button Canvas.Left="139" Canvas.Top="10" Content="s" Height="42" Width="60" />
     </Canvas>

      <Grid >
            <Button Content="01" Height="30" Width="70" Margin="20,12,414,268" />
            <Button Content="02" Height="35" Width="72" Margin="426,148,6,128" />
            <Button Content="03" Height="20" Width="74" Margin="190,122,240,170" />
            <Button Content="04" Height="25" Width="76" Margin="386,26,40,260" />
            <Button Content="05" Height="18" Width="78" Margin="376,202,48,92" />
            <Button Content="06" Height="50" Width="70" Margin="385,64,48,196" />
            <Button Content="07" Height="40" Width="72" Margin="162,202,269,68" />
            <Button Content="08" Height="55" Width="74" Margin="20,154,408,102" />
            <Button Content="09" Height="45" Width="76" Margin="21,95,406,171" />
            <Button Content="10" Height="25" Width="78" Margin="44,47,382,239" />
            <Button Content="11" Height="20" Width="80" Margin="386,120,38,170" />
            <Button Content="12" Height="30" Width="70" Margin="95,13,338,268" />
            <Button Content="13" Height="45" Width="72" Margin="290,6,140,260" />
            <Button Content="14" Height="30" Width="74" Margin="210,38,220,244" />
            <Button Content="15" Height="20" Width="76" Margin="128,48,299,242" />
            <Button Content="16" Height="25" Width="78" Margin="265,189,160,97" />
            <Button Content="17" Height="35" Width="80" Margin="176,154,246,122" />
            <Button Content="18" Height="50" Width="70" Margin="100,146,333,116" />
            <Button Content="19" Height="55" Width="72" Margin="270,121,160,135" />
            <Button Content="20" Height="45" Width="74" Margin="348,148,81,118" />
            <Button Content="21" Height="20" Width="76" Margin="94,78,332,212" />
            <Button Content="22" Height="60" Width="78" Margin="270,60,155,192" />
            <Button Content="23" Height="20" Width="80" Margin="176,74,247,216" />
            <Button Content="24" Height="25" Width="70" Margin="194,95,238,191" />
            <Button Content="25" Height="30" Width="72" Margin="117,104,314,177" />

    </Grid>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接