当数据绑定到 IEnumerable<Something> 时,网格视图如何确定列?

How does grid view determine the columns when data-bound to IEnumerable<Something>?

在试验 SharePoint 时,我创建了一个显示分区及其各自大小的简单 Web 部件。这是相关代码:

ASCX 文件:

[...]
<asp:GridView ID="diskSpaceReport" runat="server" DataSource="<%# Partitions %>">
    <Columns>
        <asp:BoundField DataField="Name" HeaderText="Name" />
        <asp:BoundField DataField="Used" HeaderText="Used" />
    </Columns>
</asp:GridView>

代码隐藏:

protected IEnumerable<Partition> Partitions
{
    get
    {
        Contract.Ensures(Contract.Result<IEnumerable<Partition>>() != null);

        return from drive in DriveInfo.GetDrives()
               let usedSpace = drive.IsReady ?
                   drive.TotalFreeSpace * 100 / drive.TotalSize : 0
               select new Partition(drive.Name, usedSpace);
    }
}

Partition.cs:

[...]
public string Name { get { ... } }
public Percentage Used { get { ... } }
[...]

这是 class 的唯一两个属性

问题

网格视图显示三列:

为了隐藏第三列,我必须将 AutoGenerateColumns="false" 添加到 <asp:GridView> 块。如果我删除 <Columns> 块,网格视图只显示一列——名称(以前是第三列)。

问题

我不明白网格视图如何自动生成列。我想当网格视图绑定到 SQL table 或类似的数据元素时效果很好,但当绑定到自定义对象的枚举时它显然会失败。

怎么找到Name 属性,但是没看懂Used也要显示?

您可以检查默认自动列生成器的源代码 here

快速浏览一下,PublicInstance properties 看起来 IsBindableType returns 是正确的。 IsBindableType 来源可用 here。它包括原始类型(int、string、dates 等),以及标有 BindableAttribute.

的类型

源代码中确定是否生成列的关键位是此处的位:

            if (type.IsPrimitive ||
                   (type == typeof(string)) ||
                   (type == typeof(DateTime)) ||
                   (type == typeof(Decimal)) ||
                   (type == typeof(Guid)) ||
                // support for new SqlServer 2008 types:
                   (type == typeof(DateTimeOffset)) ||
                   (type == typeof(TimeSpan))) {
                return true;
            }
            else {
                BindableTypeAttribute bindableTypeAttribute = (BindableTypeAttribute)TypeDescriptor.GetAttributes(type)[typeof(BindableTypeAttribute)];
                if (bindableTypeAttribute != null) {
                    return bindableTypeAttribute.IsBindable;
                }
                else {
                    //We consider enums as Bindable types by default but provide an opt-out mechanism using BindableTypeAttribute. (Ex : EntityState)
                    //So the order of above if-else block is important.
                    return (enableEnums && type.IsEnum);
                }
            }