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

如何按最大项目设置GridView项目大小,gridview,windows-store-apps,Gridview,Windows Store Apps,我试图在网格视图中显示多个项目。它之所以被选中,主要是因为它的水平滚动行为 它看起来像是GridView根据第一个项目维度定义项目大小。在下面的代码示例中,如果年份从1月开始,则会裁剪较长的月份名称,但如果第一项较宽,则会按预期显示名称 我确实想保持GridView所有项目的宽度相同,但这必须是最大项目的宽度。高度也是一样,但在我的例子中,高度是恒定的 使用GridView是否有相对简单的方法来实现这一点,或者是否有更合适的控件来实现这一点 一月 二月 ... 九月 十月 十一月 十二月

我试图在
网格视图中显示多个项目。它之所以被选中,主要是因为它的水平滚动行为

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

我确实想保持
GridView
所有项目的宽度相同,但这必须是最大项目的宽度。高度也是一样,但在我的例子中,高度是恒定的

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



一月
二月
...
九月
十月
十一月
十二月


注意:对于不同/可变的物品尺寸,有多个例子。不幸的是,这不是必需的。

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

一些被拒绝的方法是
1) 扩展
GridView
:当开发人员从GridView派生出大量有趣的信息时,实际的布局管理是在
GridView中执行的。ItemsPanel
控制和修改项目在其外部的位置需要许多黑客或脆弱的设计决策。
2) 扩展现有的
ItemPanel
容器:这将是最自然的方法,但是由于像
WrapGrid
VariableSizedWrapGrid
这样的类是密封的,这是不可能的

下面是一个将自定义面板与
GridView
一起使用的示例
如果项目太少,无法填充整个
网格视图,对齐设置会将项目放置在左上角而不是中间位置
边距补偿滚动条重叠内容的默认行为

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

您可以创建一个自定义的
GridView
类(仅从基
GridView
继承),该类覆盖
ArrangeOverride
。在安排项目时,首先它会测量所有项目(一次不能测量一个),并根据项目中最大的项目选择项目大小。@Nate Diamond谢谢,但您能否进一步阐述1-2个步骤?我询问的原因是,在调用
ArrangeOverride
期间重新安排项目将导致递归布局更新,几乎可以保证异常。此外,如果我朝这个方向走,那么定制
ItemsPanel
容器而不是
GridView
可能是有意义的。我不一定要重新安排它们。ArrangeOverride应在每个子项上调用arrange,传递该项将要给定的空间量。因此,这意味着它应该能够搜索项目的
度量值
(而不仅仅是使用第一个项目),并找到其中最大的一个。的确,这可以通过
面板来实现,比如定制
VariableSizeWrapGrid
;除非我遗漏了什么,否则就没有关于
GridView
如何定位单个项目的信息:在这一点上,如果您谈论派生类,那么
GridView
是一个黑框。不过我知道你的想法了,谢谢。这是有道理的,但仍需要更多的步骤。目前,我使用的解决方法是:继承
GridView
,在调用
MeasureOverride
ArrangeOverride
之前的某个时间对所有项目运行
Measure()
,获得最大
DesiredSize
,将其作为DP公开,并将项目的最小宽度、最小高度绑定到该值。
<GridView ... >
    <GridView.ItemsPanel>
        <ItemsPanelTemplate>
            <controls:GridViewPanel
                HorizontalAlignment="Left"
                VerticalAlignment="Top"
                Margin="0,0,0,24" />
        </ItemsPanelTemplate>
    </GridView.ItemsPanel>
    ...
</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);
    }
}