WrapPanel或自定义面板中的交错列

时间:2014-01-23 17:06:16

标签: c# .net wpf listview wpf-controls

我已经尝试了一段时间,似乎无法在不使用网格的情况下复制此模型。我已经尝试制作一些简单的自定义面板和一个,在n个像素或n个有效的项目之后创建一个新列;但是,我无法找到错开每一栏的方法。

这是我正在尝试做的事情的图像:

Layout pattern example

我制作的解决方案使用的网格错开了列,但我需要的是一个仅使用列的面板,并且像一样流畅,如果添加,移动或删除项目其他项目相应地移动(基于索引)。

1 个答案:

答案 0 :(得分:2)

因为您希望Panel有点像“生活”列表,所以解决方案需要2个步骤。首先实现一个能够按照您想要的方式排列项目的面板。第二步添加一个处理列表更改的管理器。幸运的是,这一切都很简单。这个管理器已经存在,它的ItemsControl。只需将ObserableCollection输入到ItemsControl。

        <ItemsControl Margin="10" ItemsSource="{Binding YoursItemsObserableCollection}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <local:StaggeredPanel />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <DataTemplate.Resources>
                    <Style TargetType="TextBlock">
                        <Setter Property="FontSize" Value="18"/>
                        <Setter Property="HorizontalAlignment" Value="Center"/>
                    </Style>
                </DataTemplate.Resources>
                <Grid>
                    <Ellipse Fill="Silver" Width="40" Height="40"/>
                    <StackPanel>
                        <TextBlock Margin="3,3,3,0" Text="{Binding Path=Name}"/>
                    </StackPanel>
                </Grid>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>   


class StaggeredPanel : Panel
{
    protected override Size MeasureOverride (Size availableSize)
    {
        foreach (var childo in InternalChildren)
        {
            FrameworkElement child = childo as FrameworkElement;

            if (child != null)
            {
                var childMaxSize = new Size (double.PositiveInfinity, availableSize.Height);
                child.Measure (childMaxSize);
            }
        }

        return availableSize;
    }

    protected override Size ArrangeOverride (Size finalSize)
    {
        double x = 0;
        double y = 0;
        bool shift = true;
        double shiftOffset;

        if (InternalChildren.Count > 0)
        {
            FrameworkElement offsetChild = InternalChildren[0] as FrameworkElement;
            shiftOffset = offsetChild.DesiredSize.Height / 2;

            for (int i = 0; i < InternalChildren.Count; i++)
            {
                FrameworkElement child = InternalChildren[i] as FrameworkElement;

                if (child != null)
                {
                    double finalY = y;

                    if (shift)
                    {
                        finalY += shiftOffset;
                    }

                    shift = !shift;
                    child.Arrange (new Rect (new Point (x, finalY), child.DesiredSize));

                    x += child.DesiredSize.Width;
                    double nextWidth = 0;

                    if (i + 1 < InternalChildren.Count)
                    {
                        FrameworkElement nextChild = InternalChildren[i + 1] as FrameworkElement;
                        nextWidth = child.DesiredSize.Width;
                    }

                    if (x + nextWidth > finalSize.Width)
                    {
                        shift = true;
                        x = 0;
                        y += child.DesiredSize.Height;
                    }
                }
            }
        }

        return finalSize; // Returns the final Arranged size
    }
}