13

i am working on wpf window that show list of items next each other with wrapping, i have tried to use WrapPanel in this way:

<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>

and this is the result:

enter image description here

Actually this result is unsatisfactory for me because if you imagine the WrapPanel as grid(rows and columns) you will find that there is no columns, but there are fixed size rows. i need to make WarpPanel or some control else without columns too, look at this imaginary image:

enter image description here

notice that there is no rows and no columns. this is what i wanna make.

anybody have ideas to solve this issue?

leppie
  • 115,091
  • 17
  • 196
  • 297
Heysem Katibi
  • 1,808
  • 2
  • 14
  • 29
  • i am not able to see any image.. – Bathineni Apr 08 '13 at 09:12
  • 2
    Like Clemens already wrote, you will need to write your own Panel with some sort of bin packing. [This](http://www.codeproject.com/Articles/210979/Fast-optimizing-rectangle-packing-algorithm-for-bu) might be a good article to start. – dowhilefor Apr 08 '13 at 09:57

2 Answers2

9

You could write your own custom Panel class. There are some tutorials on the web, simply google "wpf custom panel".

It boils down to overriding the MeasureOverride and ArrangeOverride methods.

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;
    }
}

UPDATE: The following simple custom Panel might more or less do what you want.

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;
    }
}
Clemens
  • 123,504
  • 12
  • 155
  • 268
  • sorry, but there are tens of must-check cases, and the check way is very complex :( is this the only way to make the desired panel? – Heysem Katibi Apr 08 '13 at 11:54
  • Not sure what exactly you mean with "must-check cases", but the calculation needed to arrange the child elements have to be done somewhere. If you can't find an existing Panel class with the desired behaviour (and I doubt you can), you will have to do it yourself. – Clemens Apr 08 '13 at 16:47
-1

You Can Either use Canvas:

Or Use Grid and set the Margin of each Buttons according to requirenment

     <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>
YOusaFZai
  • 698
  • 5
  • 21