如何按最大项设置GridView项目大小

时间:2014-05-22 19:26:05

标签: gridview windows-store-apps

我试图在GridView中显示多个项目。它的选择主要是因为它的水平滚动行为。

看起来GridView根据第一个项目维度定义项目大小。在下面的代码示例中,如果年份从1月份开始,则会裁剪较长的月份名称,但如果第一个项目较宽,则会按预期显示名称。

我确实希望GridView保持所有宽度相同的项目,但必须是最大项目的宽度。高度相同,但在我的情况下,高度是恒定的。

使用GridView是否有相对简单的方法来实现这一目标,或者可能有更合适的控件?


<GridView>
    <GridView.Items>
        <x:String>January</x:String>
        <x:String>February</x:String>
        <x:String>...</x:String>
        <x:String>September</x:String>
        <x:String>October</x:String>
        <x:String>November</x:String>
        <x:String>December</x:String>
    </GridView.Items>
</GridView>

GridView output

N.B。那里有不同/可变项目大小的多个示例。不幸的是,需要什么。

1 个答案:

答案 0 :(得分:0)

经过一些研究,满足要求的最简单方法是使用ItemsPanelTemplate中的自定义面板。

一些被拒绝的方法是 1)扩展GridView:当开发人员从GridView派生时可以访问大量有趣的信息时,实际的布局管理在GridView.ItemsPanel控件中执行,修改项目位置以外的位置需要一些黑客或脆弱的设计决定 2)扩展现有的ItemPanel容器:这是最自然的方法,但由于WrapGridVariableSizedWrapGrid等类是密封的,因此无法实现。

以下是使用GridView的自定义面板的示例 如果整个GridView中的项目太少,则对齐设置会在左上角而不是中心定位项目。
保证金补偿滚动条的默认行为以重叠内容。

<GridView ... >
    <GridView.ItemsPanel>
        <ItemsPanelTemplate>
            <controls:GridViewPanel
                HorizontalAlignment="Left"
                VerticalAlignment="Top"
                Margin="0,0,0,24" />
        </ItemsPanelTemplate>
    </GridView.ItemsPanel>
    ...
</GridView>

完整的自定义面板代码如下。它有意简化,但可以轻松扩展以满足特定的附加要求,例如更精确的布局控制,可变列宽,虚拟化等。虽然使用更高级GridView功能(如分组),但尚未对其进行测试。

using System;
using Windows.Foundation;
using Windows.UI.Xaml.Controls;

/// <summary>
/// Uniformly positions child items in columns to present in WrapGrid.
/// Uses largest item's DesiredSize for item size mesasurements.
/// Expects limited height and unbound width.
/// </summary>
public class GridViewPanel : Panel
{
    protected override Size MeasureOverride(Size availableSize)
    {
        return ArrangeInternal(availableSize, callArrange: false);
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        return ArrangeInternal(finalSize);
    }

    private Size ArrangeInternal(Size size, bool callArrange = true)
    {
        // measure max desired item size
        //
        double itemWidth = 0.0, itemHeight = 0.0;
        foreach (var item in Children)
        {
            item.Measure(size);
            itemWidth = Math.Max(itemWidth, item.DesiredSize.Width);
            itemHeight = Math.Max(itemHeight, item.DesiredSize.Height);
        }
        // requested item height can't exceed total available height
        itemHeight = Math.Min(itemHeight, size.Height);

        // position each child and get total content size
        //
        double totalWidth = 0.0, totalHeight = 0.0;
        double x = 0.0, y = 0.0;

        foreach (var item in Children)
        {
            if (y + itemHeight > size.Height)
            {
                // if item won't fit, move to the next column
                totalHeight = Math.Max(totalHeight, y);
                y = 0;
                x += itemWidth;
            }

            // implicitly, item fits in current column
            if (callArrange) item.Arrange(new Rect(x, y, itemWidth, itemHeight));
            y += itemHeight;
        }

        totalWidth = x + itemWidth;
        totalHeight = Math.Max(totalHeight, y);

        return new Size(totalWidth, totalHeight);
    }
}